110802Srene.dejong@arm.com/*
210802Srene.dejong@arm.com * Copyright (c) 2013-2015 ARM Limited
310802Srene.dejong@arm.com * All rights reserved
410802Srene.dejong@arm.com *
510802Srene.dejong@arm.com * The license below extends only to copyright in the software and shall
610802Srene.dejong@arm.com * not be construed as granting a license to any other intellectual
710802Srene.dejong@arm.com * property including but not limited to intellectual property relating
810802Srene.dejong@arm.com * to a hardware implementation of the functionality of the software
910802Srene.dejong@arm.com * licensed hereunder.  You may use the software subject to the license
1010802Srene.dejong@arm.com * terms below provided that you ensure that this notice is replicated
1110802Srene.dejong@arm.com * unmodified and in its entirety in all distributions of the software,
1210802Srene.dejong@arm.com * modified or unmodified, in source code or in binary form.
1310802Srene.dejong@arm.com *
1410802Srene.dejong@arm.com * Redistribution and use in source and binary forms, with or without
1510802Srene.dejong@arm.com * modification, are permitted provided that the following conditions are
1610802Srene.dejong@arm.com * met: redistributions of source code must retain the above copyright
1710802Srene.dejong@arm.com * notice, this list of conditions and the following disclaimer;
1810802Srene.dejong@arm.com * redistributions in binary form must reproduce the above copyright
1910802Srene.dejong@arm.com * notice, this list of conditions and the following disclaimer in the
2010802Srene.dejong@arm.com * documentation and/or other materials provided with the distribution;
2110802Srene.dejong@arm.com * neither the name of the copyright holders nor the names of its
2210802Srene.dejong@arm.com * contributors may be used to endorse or promote products derived from
2310802Srene.dejong@arm.com * this software without specific prior written permission.
2410802Srene.dejong@arm.com *
2510802Srene.dejong@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610802Srene.dejong@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710802Srene.dejong@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810802Srene.dejong@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910802Srene.dejong@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010802Srene.dejong@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110802Srene.dejong@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210802Srene.dejong@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310802Srene.dejong@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410802Srene.dejong@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510802Srene.dejong@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610802Srene.dejong@arm.com *
3710802Srene.dejong@arm.com * Authors: Rene de Jong
3810802Srene.dejong@arm.com */
3910802Srene.dejong@arm.com
4010802Srene.dejong@arm.com/** @file
4110802Srene.dejong@arm.com * This is a simulation model for a UFS interface
4210802Srene.dejong@arm.com * The UFS interface consists of a host controller and (at least) one device.
4310802Srene.dejong@arm.com * The device can contain multiple logic units.
4410802Srene.dejong@arm.com * To make this interface as usefull as possible for future development, the
4510802Srene.dejong@arm.com * decision has been made to split the UFS functionality from the SCSI
4610802Srene.dejong@arm.com * functionality. The class UFS SCSIDevice can therefor be used as a starting
4710802Srene.dejong@arm.com * point for creating a more generic SCSI device. This has as a consequence
4810802Srene.dejong@arm.com * that the UFSHostDevice class contains functionality from both the host
4910802Srene.dejong@arm.com * controller and the device. The current UFS standard (1.1) allows only one
5010802Srene.dejong@arm.com * device, and up to 8 logic units. the logic units only handle the SCSI part
5110802Srene.dejong@arm.com * of the command, and the device mainly the UFS part. Yet the split between
5210802Srene.dejong@arm.com * the SCSIresume function and the SCSICMDHandle might seem a bit awkward.
5310802Srene.dejong@arm.com * The SCSICMDHandle function is in essence a SCSI reply generator, and it
5410802Srene.dejong@arm.com * distils the essential information from the command. A disktransfer cannot
5510802Srene.dejong@arm.com * be made from this position because the scatter gather list is not included
5610802Srene.dejong@arm.com * in the SCSI command, but in the Transfer Request descriptor. The device
5710802Srene.dejong@arm.com * needs to manage the data transfer. This file is build up as follows: first
5810802Srene.dejong@arm.com * the UFSSCSIDevice functions will be presented; then the UFSHostDevice
5910802Srene.dejong@arm.com * functions. The UFSHostDevice functions are split in three parts: UFS
6010802Srene.dejong@arm.com * transaction flow, data write transfer and data read transfer. The
6110802Srene.dejong@arm.com * functions are then ordered in the order in which a transfer takes place.
6210802Srene.dejong@arm.com */
6310802Srene.dejong@arm.com
6410802Srene.dejong@arm.com/**
6510802Srene.dejong@arm.com * Reference material can be found at the JEDEC website:
6610802Srene.dejong@arm.com * UFS standard
6710802Srene.dejong@arm.com * http://www.jedec.org/standards-documents/results/jesd220
6810802Srene.dejong@arm.com * UFS HCI specification
6910802Srene.dejong@arm.com * http://www.jedec.org/standards-documents/results/jesd223
7010802Srene.dejong@arm.com */
7110802Srene.dejong@arm.com
7210802Srene.dejong@arm.com#include "dev/arm/ufs_device.hh"
7310802Srene.dejong@arm.com
7410802Srene.dejong@arm.com/**
7510802Srene.dejong@arm.com * Constructor and destructor functions of UFSHCM device
7610802Srene.dejong@arm.com */
7710802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::UFSSCSIDevice(const UFSHostDeviceParams* p,
7810802Srene.dejong@arm.com                             uint32_t lun_id, Callback *transfer_cb,
7910802Srene.dejong@arm.com                             Callback *read_cb):
8010802Srene.dejong@arm.com    SimObject(p),
8110802Srene.dejong@arm.com    flashDisk(p->image[lun_id]),
8210802Srene.dejong@arm.com    flashDevice(p->internalflash[lun_id]),
8310802Srene.dejong@arm.com    blkSize(p->img_blk_size),
8410802Srene.dejong@arm.com    lunAvail(p->image.size()),
8510802Srene.dejong@arm.com    diskSize(flashDisk->size()),
8610802Srene.dejong@arm.com    capacityLower((diskSize - 1) & 0xffffffff),
8710802Srene.dejong@arm.com    capacityUpper((diskSize - SectorSize) >> 32),
8810802Srene.dejong@arm.com    lunID(lun_id),
8910802Srene.dejong@arm.com    transferCompleted(false),
9010802Srene.dejong@arm.com    readCompleted(false),
9110802Srene.dejong@arm.com    totalRead(0),
9210802Srene.dejong@arm.com    totalWrite(0),
9310802Srene.dejong@arm.com    amountOfWriteTransfers(0),
9410802Srene.dejong@arm.com    amountOfReadTransfers(0)
9510802Srene.dejong@arm.com{
9610802Srene.dejong@arm.com    /**
9710802Srene.dejong@arm.com     * These callbacks are used to communicate the events that are
9810802Srene.dejong@arm.com     * triggered upstream; e.g. from the Memory Device to the UFS SCSI Device
9910802Srene.dejong@arm.com     * or from the UFS SCSI device to the UFS host.
10010802Srene.dejong@arm.com     */
10110802Srene.dejong@arm.com    signalDone = transfer_cb;
10210802Srene.dejong@arm.com    memReadCallback = new MakeCallback<UFSSCSIDevice,
10310802Srene.dejong@arm.com        &UFSHostDevice::UFSSCSIDevice::readCallback>(this);
10410802Srene.dejong@arm.com    deviceReadCallback = read_cb;
10510802Srene.dejong@arm.com    memWriteCallback = new MakeCallback<UFSSCSIDevice,
10610802Srene.dejong@arm.com        &UFSHostDevice::UFSSCSIDevice::SSDWriteDone>(this);
10710802Srene.dejong@arm.com
10810802Srene.dejong@arm.com    /**
10910802Srene.dejong@arm.com     * make ascii out of lun_id (and add more characters)
11010802Srene.dejong@arm.com     * UFS allows up to 8 logic units, so the numbering should work out
11110802Srene.dejong@arm.com     */
11210802Srene.dejong@arm.com    uint32_t temp_id = ((lun_id | 0x30) << 24) | 0x3A4449;
11310802Srene.dejong@arm.com    lunInfo.dWord0 = 0x02060000;   //data
11410802Srene.dejong@arm.com    lunInfo.dWord1 = 0x0200001F;
11510802Srene.dejong@arm.com    lunInfo.vendor0 = 0x484D5241;  //ARMH (HMRA)
11610802Srene.dejong@arm.com    lunInfo.vendor1 = 0x424D4143;  //CAMB (BMAC)
11710802Srene.dejong@arm.com    lunInfo.product0 = 0x356D6567; //gem5  (5meg)
11810802Srene.dejong@arm.com    lunInfo.product1 = 0x4D534655; //UFSM (MSFU)
11910802Srene.dejong@arm.com    lunInfo.product2 = 0x4C45444F; //ODEL (LEDO)
12010802Srene.dejong@arm.com    lunInfo.product3 = temp_id;    // ID:"lun_id" ("lun_id":DI)
12110802Srene.dejong@arm.com    lunInfo.productRevision = 0x01000000; //0x01
12210802Srene.dejong@arm.com
12310802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Logic unit %d assumes that %d logic units are"
12410802Srene.dejong@arm.com            " present in the system\n", lunID, lunAvail);
12510802Srene.dejong@arm.com    DPRINTF(UFSHostDevice,"The disksize of lun: %d should be %d blocks\n",
12610802Srene.dejong@arm.com            lunID, diskSize);
12710802Srene.dejong@arm.com    flashDevice->initializeMemory(diskSize, SectorSize);
12810802Srene.dejong@arm.com}
12910802Srene.dejong@arm.com
13010802Srene.dejong@arm.com
13110802Srene.dejong@arm.com/**
13210802Srene.dejong@arm.com * These pages are SCSI specific. For more information refer to:
13310802Srene.dejong@arm.com * Universal Flash Storage (UFS) JESD220 FEB 2011 (JEDEC)
13410802Srene.dejong@arm.com * http://www.jedec.org/standards-documents/results/jesd220
13510802Srene.dejong@arm.com */
13610802Srene.dejong@arm.comconst unsigned int UFSHostDevice::UFSSCSIDevice::controlPage[3] =
13710802Srene.dejong@arm.com                                                {0x01400A0A, 0x00000000,
13810802Srene.dejong@arm.com                                                 0x0000FFFF};
13910802Srene.dejong@arm.comconst unsigned int UFSHostDevice::UFSSCSIDevice::recoveryPage[3] =
14010802Srene.dejong@arm.com                                                {0x03800A01, 0x00000000,
14110802Srene.dejong@arm.com                                                 0xFFFF0003};
14210802Srene.dejong@arm.comconst unsigned int UFSHostDevice::UFSSCSIDevice::cachingPage[5] =
14310802Srene.dejong@arm.com                                                {0x00011208, 0x00000000,
14410802Srene.dejong@arm.com                                                 0x00000000, 0x00000020,
14510802Srene.dejong@arm.com                                                 0x00000000};
14610802Srene.dejong@arm.com
14710802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::~UFSSCSIDevice() {}
14810802Srene.dejong@arm.com
14910802Srene.dejong@arm.com/**
15010802Srene.dejong@arm.com * UFS specific SCSI handling function.
15110802Srene.dejong@arm.com * The following attributes may still be added: SCSI format unit,
15210802Srene.dejong@arm.com * Send diagnostic and UNMAP;
15310802Srene.dejong@arm.com * Synchronize Cache and buffer read/write could not be tested yet
15410802Srene.dejong@arm.com * All parameters can be found in:
15510802Srene.dejong@arm.com * Universal Flash Storage (UFS) JESD220 FEB 2011 (JEDEC)
15610802Srene.dejong@arm.com * http://www.jedec.org/standards-documents/results/jesd220
15710802Srene.dejong@arm.com * (a JEDEC acount may be required {free of charge})
15810802Srene.dejong@arm.com */
15910802Srene.dejong@arm.com
16010802Srene.dejong@arm.comstruct UFSHostDevice::SCSIReply
16110802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SCSICMDHandle(uint32_t* SCSI_msg)
16210802Srene.dejong@arm.com{
16310802Srene.dejong@arm.com    struct SCSIReply scsi_out;
16413025Smadnaurice@googlemail.com    scsi_out.reset();
16510802Srene.dejong@arm.com
16610802Srene.dejong@arm.com    /**
16710802Srene.dejong@arm.com     * Create the standard SCSI reponse information
16810802Srene.dejong@arm.com     * These values might changes over the course of a transfer
16910802Srene.dejong@arm.com     */
17010802Srene.dejong@arm.com    scsi_out.message.header.dWord0 = UPIUHeaderDataIndWord0 |
17110802Srene.dejong@arm.com        lunID << 16;
17210802Srene.dejong@arm.com    scsi_out.message.header.dWord1 = UPIUHeaderDataIndWord1;
17310802Srene.dejong@arm.com    scsi_out.message.header.dWord2 = UPIUHeaderDataIndWord2;
17410802Srene.dejong@arm.com    statusCheck(SCSIGood, scsi_out.senseCode);
17510802Srene.dejong@arm.com    scsi_out.senseSize = scsi_out.senseCode[0];
17610802Srene.dejong@arm.com    scsi_out.LUN = lunID;
17710802Srene.dejong@arm.com    scsi_out.status = SCSIGood;
17810802Srene.dejong@arm.com
17910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI command:%2x\n", SCSI_msg[4]);
18010802Srene.dejong@arm.com    /**Determine what the message is and fill the response packet*/
18110802Srene.dejong@arm.com
18210802Srene.dejong@arm.com    switch (SCSI_msg[4] & 0xFF) {
18310802Srene.dejong@arm.com
18410802Srene.dejong@arm.com      case SCSIInquiry: {
18510802Srene.dejong@arm.com          /**
18610802Srene.dejong@arm.com           * SCSI inquiry: tell about this specific logic unit
18710802Srene.dejong@arm.com           */
18810802Srene.dejong@arm.com          scsi_out.msgSize = 36;
18910802Srene.dejong@arm.com          scsi_out.message.dataMsg.resize(9);
19010802Srene.dejong@arm.com
19110802Srene.dejong@arm.com          for (uint8_t count = 0; count < 9; count++)
19210802Srene.dejong@arm.com              scsi_out.message.dataMsg[count] =
19310802Srene.dejong@arm.com                  (reinterpret_cast<uint32_t*> (&lunInfo))[count];
19410802Srene.dejong@arm.com      } break;
19510802Srene.dejong@arm.com
19610802Srene.dejong@arm.com      case SCSIRead6: {
19710802Srene.dejong@arm.com          /**
19810802Srene.dejong@arm.com           * Read command. Number indicates the length of the command.
19910802Srene.dejong@arm.com           */
20010802Srene.dejong@arm.com          scsi_out.expectMore = 0x02;
20110802Srene.dejong@arm.com          scsi_out.msgSize = 0;
20210802Srene.dejong@arm.com
20310802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
20410802Srene.dejong@arm.com
20510802Srene.dejong@arm.com          /**BE and not nicely aligned. Apart from that it only has
20610802Srene.dejong@arm.com           * information in five bits of the first byte that is relevant
20710802Srene.dejong@arm.com           * for this field.
20810802Srene.dejong@arm.com           */
20910802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
21010802Srene.dejong@arm.com          uint64_t read_offset = betoh(tmp) & 0x1FFFFF;
21110802Srene.dejong@arm.com
21210802Srene.dejong@arm.com          uint32_t read_size = tempptr[4];
21310802Srene.dejong@arm.com
21410802Srene.dejong@arm.com
21510802Srene.dejong@arm.com          scsi_out.msgSize =  read_size * blkSize;
21610802Srene.dejong@arm.com          scsi_out.offset = read_offset * blkSize;
21710802Srene.dejong@arm.com
21810802Srene.dejong@arm.com          if ((read_offset + read_size) > diskSize)
21910802Srene.dejong@arm.com              scsi_out.status = SCSIIllegalRequest;
22010802Srene.dejong@arm.com
22110802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Read6 offset: 0x%8x, for %d blocks\n",
22210802Srene.dejong@arm.com                  read_offset, read_size);
22310802Srene.dejong@arm.com
22410802Srene.dejong@arm.com          /**
22510802Srene.dejong@arm.com           * Renew status check, for the request may have been illegal
22610802Srene.dejong@arm.com           */
22710802Srene.dejong@arm.com          statusCheck(scsi_out.status, scsi_out.senseCode);
22810802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
22910802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
23010802Srene.dejong@arm.com              SCSICheckCondition;
23110802Srene.dejong@arm.com
23210802Srene.dejong@arm.com      } break;
23310802Srene.dejong@arm.com
23410802Srene.dejong@arm.com      case SCSIRead10: {
23510802Srene.dejong@arm.com          scsi_out.expectMore = 0x02;
23610802Srene.dejong@arm.com          scsi_out.msgSize = 0;
23710802Srene.dejong@arm.com
23810802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
23910802Srene.dejong@arm.com
24010802Srene.dejong@arm.com          /**BE and not nicely aligned.*/
24110802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
24210802Srene.dejong@arm.com          uint64_t read_offset = betoh(tmp);
24310802Srene.dejong@arm.com
24410802Srene.dejong@arm.com          uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
24510802Srene.dejong@arm.com          uint32_t read_size = betoh(tmpsize);
24610802Srene.dejong@arm.com
24710802Srene.dejong@arm.com          scsi_out.msgSize =  read_size * blkSize;
24810802Srene.dejong@arm.com          scsi_out.offset = read_offset * blkSize;
24910802Srene.dejong@arm.com
25010802Srene.dejong@arm.com          if ((read_offset + read_size) > diskSize)
25110802Srene.dejong@arm.com              scsi_out.status = SCSIIllegalRequest;
25210802Srene.dejong@arm.com
25310802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Read10 offset: 0x%8x, for %d blocks\n",
25410802Srene.dejong@arm.com                  read_offset, read_size);
25510802Srene.dejong@arm.com
25610802Srene.dejong@arm.com          /**
25710802Srene.dejong@arm.com           * Renew status check, for the request may have been illegal
25810802Srene.dejong@arm.com           */
25910802Srene.dejong@arm.com          statusCheck(scsi_out.status, scsi_out.senseCode);
26010802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
26110802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
26210802Srene.dejong@arm.com              SCSICheckCondition;
26310802Srene.dejong@arm.com
26410802Srene.dejong@arm.com      } break;
26510802Srene.dejong@arm.com
26610802Srene.dejong@arm.com      case SCSIRead16: {
26710802Srene.dejong@arm.com          scsi_out.expectMore = 0x02;
26810802Srene.dejong@arm.com          scsi_out.msgSize = 0;
26910802Srene.dejong@arm.com
27010802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
27110802Srene.dejong@arm.com
27210802Srene.dejong@arm.com          /**BE and not nicely aligned.*/
27310802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
27410802Srene.dejong@arm.com          uint64_t read_offset = betoh(tmp);
27510802Srene.dejong@arm.com
27610802Srene.dejong@arm.com          tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
27710802Srene.dejong@arm.com          read_offset = (read_offset << 32) | betoh(tmp);
27810802Srene.dejong@arm.com
27910802Srene.dejong@arm.com          tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
28010802Srene.dejong@arm.com          uint32_t read_size = betoh(tmp);
28110802Srene.dejong@arm.com
28210802Srene.dejong@arm.com          scsi_out.msgSize =  read_size * blkSize;
28310802Srene.dejong@arm.com          scsi_out.offset = read_offset * blkSize;
28410802Srene.dejong@arm.com
28510802Srene.dejong@arm.com          if ((read_offset + read_size) > diskSize)
28610802Srene.dejong@arm.com              scsi_out.status = SCSIIllegalRequest;
28710802Srene.dejong@arm.com
28810802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Read16 offset: 0x%8x, for %d blocks\n",
28910802Srene.dejong@arm.com                  read_offset, read_size);
29010802Srene.dejong@arm.com
29110802Srene.dejong@arm.com          /**
29210802Srene.dejong@arm.com           * Renew status check, for the request may have been illegal
29310802Srene.dejong@arm.com           */
29410802Srene.dejong@arm.com          statusCheck(scsi_out.status, scsi_out.senseCode);
29510802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
29610802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
29710802Srene.dejong@arm.com              SCSICheckCondition;
29810802Srene.dejong@arm.com
29910802Srene.dejong@arm.com      } break;
30010802Srene.dejong@arm.com
30110802Srene.dejong@arm.com      case SCSIReadCapacity10: {
30210802Srene.dejong@arm.com          /**
30310802Srene.dejong@arm.com           * read the capacity of the device
30410802Srene.dejong@arm.com           */
30510802Srene.dejong@arm.com          scsi_out.msgSize = 8;
30610802Srene.dejong@arm.com          scsi_out.message.dataMsg.resize(2);
30710802Srene.dejong@arm.com          scsi_out.message.dataMsg[0] =
30810802Srene.dejong@arm.com              betoh(capacityLower);//last block
30910802Srene.dejong@arm.com          scsi_out.message.dataMsg[1] = betoh(blkSize);//blocksize
31010802Srene.dejong@arm.com
31110802Srene.dejong@arm.com      } break;
31210802Srene.dejong@arm.com      case SCSIReadCapacity16: {
31310802Srene.dejong@arm.com          scsi_out.msgSize = 32;
31410802Srene.dejong@arm.com          scsi_out.message.dataMsg.resize(8);
31510802Srene.dejong@arm.com          scsi_out.message.dataMsg[0] =
31610802Srene.dejong@arm.com              betoh(capacityUpper);//last block
31710802Srene.dejong@arm.com          scsi_out.message.dataMsg[1] =
31810802Srene.dejong@arm.com              betoh(capacityLower);//last block
31910802Srene.dejong@arm.com          scsi_out.message.dataMsg[2] = betoh(blkSize);//blocksize
32010802Srene.dejong@arm.com          scsi_out.message.dataMsg[3] = 0x00;//
32110802Srene.dejong@arm.com          scsi_out.message.dataMsg[4] = 0x00;//reserved
32210802Srene.dejong@arm.com          scsi_out.message.dataMsg[5] = 0x00;//reserved
32310802Srene.dejong@arm.com          scsi_out.message.dataMsg[6] = 0x00;//reserved
32410802Srene.dejong@arm.com          scsi_out.message.dataMsg[7] = 0x00;//reserved
32510802Srene.dejong@arm.com
32610802Srene.dejong@arm.com      } break;
32710802Srene.dejong@arm.com
32810802Srene.dejong@arm.com      case SCSIReportLUNs: {
32910802Srene.dejong@arm.com          /**
33010802Srene.dejong@arm.com           * Find out how many Logic Units this device has.
33110802Srene.dejong@arm.com           */
33210802Srene.dejong@arm.com          scsi_out.msgSize = (lunAvail * 8) + 8;//list + overhead
33310802Srene.dejong@arm.com          scsi_out.message.dataMsg.resize(2 * lunAvail + 2);
33410802Srene.dejong@arm.com          scsi_out.message.dataMsg[0] = (lunAvail * 8) << 24;//LUN listlength
33510802Srene.dejong@arm.com          scsi_out.message.dataMsg[1] = 0x00;
33610802Srene.dejong@arm.com
33710802Srene.dejong@arm.com          for (uint8_t count = 0; count < lunAvail; count++) {
33810802Srene.dejong@arm.com              //LUN "count"
33910802Srene.dejong@arm.com              scsi_out.message.dataMsg[2 + 2 * count] = (count & 0x7F) << 8;
34010802Srene.dejong@arm.com              scsi_out.message.dataMsg[3 + 2 * count] = 0x00;
34110802Srene.dejong@arm.com          }
34210802Srene.dejong@arm.com
34310802Srene.dejong@arm.com      } break;
34410802Srene.dejong@arm.com
34510802Srene.dejong@arm.com      case SCSIStartStop: {
34610802Srene.dejong@arm.com          //Just acknowledge; not deemed relevant ATM
34710802Srene.dejong@arm.com          scsi_out.msgSize = 0;
34810802Srene.dejong@arm.com
34910802Srene.dejong@arm.com      } break;
35010802Srene.dejong@arm.com
35110802Srene.dejong@arm.com      case SCSITestUnitReady: {
35210802Srene.dejong@arm.com          //Just acknowledge; not deemed relevant ATM
35310802Srene.dejong@arm.com          scsi_out.msgSize = 0;
35410802Srene.dejong@arm.com
35510802Srene.dejong@arm.com      } break;
35610802Srene.dejong@arm.com
35710802Srene.dejong@arm.com      case SCSIVerify10: {
35810802Srene.dejong@arm.com          /**
35910802Srene.dejong@arm.com           * See if the blocks that the host plans to request are in range of
36010802Srene.dejong@arm.com           * the device.
36110802Srene.dejong@arm.com           */
36210802Srene.dejong@arm.com          scsi_out.msgSize = 0;
36310802Srene.dejong@arm.com
36410802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
36510802Srene.dejong@arm.com
36610802Srene.dejong@arm.com          /**BE and not nicely aligned.*/
36710802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
36810802Srene.dejong@arm.com          uint64_t read_offset = betoh(tmp);
36910802Srene.dejong@arm.com
37010802Srene.dejong@arm.com          uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
37110802Srene.dejong@arm.com          uint32_t read_size = betoh(tmpsize);
37210802Srene.dejong@arm.com
37310802Srene.dejong@arm.com          if ((read_offset + read_size) > diskSize)
37410802Srene.dejong@arm.com              scsi_out.status = SCSIIllegalRequest;
37510802Srene.dejong@arm.com
37610802Srene.dejong@arm.com          /**
37710802Srene.dejong@arm.com           * Renew status check, for the request may have been illegal
37810802Srene.dejong@arm.com           */
37910802Srene.dejong@arm.com          statusCheck(scsi_out.status, scsi_out.senseCode);
38010802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
38110802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
38210802Srene.dejong@arm.com              SCSICheckCondition;
38310802Srene.dejong@arm.com
38410802Srene.dejong@arm.com      } break;
38510802Srene.dejong@arm.com
38610802Srene.dejong@arm.com      case SCSIWrite6: {
38710802Srene.dejong@arm.com          /**
38810802Srene.dejong@arm.com           * Write command.
38910802Srene.dejong@arm.com           */
39010802Srene.dejong@arm.com
39110802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
39210802Srene.dejong@arm.com
39310802Srene.dejong@arm.com          /**BE and not nicely aligned. Apart from that it only has
39410802Srene.dejong@arm.com           * information in five bits of the first byte that is relevant
39510802Srene.dejong@arm.com           * for this field.
39610802Srene.dejong@arm.com           */
39710802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
39810802Srene.dejong@arm.com          uint64_t write_offset = betoh(tmp) & 0x1FFFFF;
39910802Srene.dejong@arm.com
40010802Srene.dejong@arm.com          uint32_t write_size = tempptr[4];
40110802Srene.dejong@arm.com
40210802Srene.dejong@arm.com          scsi_out.msgSize =  write_size * blkSize;
40310802Srene.dejong@arm.com          scsi_out.offset = write_offset * blkSize;
40410802Srene.dejong@arm.com          scsi_out.expectMore = 0x01;
40510802Srene.dejong@arm.com
40610802Srene.dejong@arm.com          if ((write_offset + write_size) > diskSize)
40710802Srene.dejong@arm.com              scsi_out.status = SCSIIllegalRequest;
40810802Srene.dejong@arm.com
40910802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Write6 offset: 0x%8x, for %d blocks\n",
41010802Srene.dejong@arm.com                  write_offset, write_size);
41110802Srene.dejong@arm.com
41210802Srene.dejong@arm.com          /**
41310802Srene.dejong@arm.com           * Renew status check, for the request may have been illegal
41410802Srene.dejong@arm.com           */
41510802Srene.dejong@arm.com          statusCheck(scsi_out.status, scsi_out.senseCode);
41610802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
41710802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
41810802Srene.dejong@arm.com              SCSICheckCondition;
41910802Srene.dejong@arm.com
42010802Srene.dejong@arm.com      } break;
42110802Srene.dejong@arm.com
42210802Srene.dejong@arm.com      case SCSIWrite10: {
42310802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
42410802Srene.dejong@arm.com
42510802Srene.dejong@arm.com          /**BE and not nicely aligned.*/
42610802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
42710802Srene.dejong@arm.com          uint64_t write_offset = betoh(tmp);
42810802Srene.dejong@arm.com
42910802Srene.dejong@arm.com          uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
43010802Srene.dejong@arm.com          uint32_t write_size = betoh(tmpsize);
43110802Srene.dejong@arm.com
43210802Srene.dejong@arm.com          scsi_out.msgSize =  write_size * blkSize;
43310802Srene.dejong@arm.com          scsi_out.offset = write_offset * blkSize;
43410802Srene.dejong@arm.com          scsi_out.expectMore = 0x01;
43510802Srene.dejong@arm.com
43610802Srene.dejong@arm.com          if ((write_offset + write_size) > diskSize)
43710802Srene.dejong@arm.com              scsi_out.status = SCSIIllegalRequest;
43810802Srene.dejong@arm.com
43910802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Write10 offset: 0x%8x, for %d blocks\n",
44010802Srene.dejong@arm.com                  write_offset, write_size);
44110802Srene.dejong@arm.com
44210802Srene.dejong@arm.com          /**
44310802Srene.dejong@arm.com           * Renew status check, for the request may have been illegal
44410802Srene.dejong@arm.com           */
44510802Srene.dejong@arm.com          statusCheck(scsi_out.status, scsi_out.senseCode);
44610802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
44710802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
44810802Srene.dejong@arm.com              SCSICheckCondition;
44910802Srene.dejong@arm.com
45010802Srene.dejong@arm.com      } break;
45110802Srene.dejong@arm.com
45210802Srene.dejong@arm.com      case SCSIWrite16: {
45310802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
45410802Srene.dejong@arm.com
45510802Srene.dejong@arm.com          /**BE and not nicely aligned.*/
45610802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
45710802Srene.dejong@arm.com          uint64_t write_offset = betoh(tmp);
45810802Srene.dejong@arm.com
45910802Srene.dejong@arm.com          tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
46010802Srene.dejong@arm.com          write_offset = (write_offset << 32) | betoh(tmp);
46110802Srene.dejong@arm.com
46210802Srene.dejong@arm.com          tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
46310802Srene.dejong@arm.com          uint32_t write_size = betoh(tmp);
46410802Srene.dejong@arm.com
46510802Srene.dejong@arm.com          scsi_out.msgSize = write_size * blkSize;
46610802Srene.dejong@arm.com          scsi_out.offset = write_offset * blkSize;
46710802Srene.dejong@arm.com          scsi_out.expectMore = 0x01;
46810802Srene.dejong@arm.com
46910802Srene.dejong@arm.com          if ((write_offset + write_size) > diskSize)
47010802Srene.dejong@arm.com              scsi_out.status = SCSIIllegalRequest;
47110802Srene.dejong@arm.com
47210802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Write16 offset: 0x%8x, for %d blocks\n",
47310802Srene.dejong@arm.com                  write_offset, write_size);
47410802Srene.dejong@arm.com
47510802Srene.dejong@arm.com          /**
47610802Srene.dejong@arm.com           * Renew status check, for the request may have been illegal
47710802Srene.dejong@arm.com           */
47810802Srene.dejong@arm.com          statusCheck(scsi_out.status, scsi_out.senseCode);
47910802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
48010802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
48110802Srene.dejong@arm.com              SCSICheckCondition;
48210802Srene.dejong@arm.com
48310802Srene.dejong@arm.com      } break;
48410802Srene.dejong@arm.com
48510802Srene.dejong@arm.com      case SCSIFormatUnit: {//not yet verified
48610802Srene.dejong@arm.com          scsi_out.msgSize = 0;
48710802Srene.dejong@arm.com          scsi_out.expectMore = 0x01;
48810802Srene.dejong@arm.com
48910802Srene.dejong@arm.com      } break;
49010802Srene.dejong@arm.com
49110802Srene.dejong@arm.com      case SCSISendDiagnostic: {//not yet verified
49210802Srene.dejong@arm.com          scsi_out.msgSize = 0;
49310802Srene.dejong@arm.com
49410802Srene.dejong@arm.com      } break;
49510802Srene.dejong@arm.com
49610802Srene.dejong@arm.com      case SCSISynchronizeCache: {
49710802Srene.dejong@arm.com          //do we have cache (we don't have cache at this moment)
49810802Srene.dejong@arm.com          //TODO: here will synchronization happen when cache is modelled
49910802Srene.dejong@arm.com          scsi_out.msgSize = 0;
50010802Srene.dejong@arm.com
50110802Srene.dejong@arm.com      } break;
50210802Srene.dejong@arm.com
50310802Srene.dejong@arm.com        //UFS SCSI additional command set for full functionality
50410802Srene.dejong@arm.com      case SCSIModeSelect10:
50510802Srene.dejong@arm.com        //TODO:
50610802Srene.dejong@arm.com        //scsi_out.expectMore = 0x01;//not supported due to modepage support
50710802Srene.dejong@arm.com        //code isn't dead, code suggest what is to be done when implemented
50810802Srene.dejong@arm.com        break;
50910802Srene.dejong@arm.com
51010802Srene.dejong@arm.com      case SCSIModeSense6: case SCSIModeSense10: {
51110802Srene.dejong@arm.com          /**
51210802Srene.dejong@arm.com           * Get more discriptive information about the SCSI functionality
51310802Srene.dejong@arm.com           * within this logic unit.
51410802Srene.dejong@arm.com           */
51510802Srene.dejong@arm.com          if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x0A) {//control page
51610802Srene.dejong@arm.com              scsi_out.message.dataMsg.resize((sizeof(controlPage) >> 2) + 2);
51710802Srene.dejong@arm.com              scsi_out.message.dataMsg[0] = 0x00000A00;//control page code
51810802Srene.dejong@arm.com              scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
51910802Srene.dejong@arm.com
52010802Srene.dejong@arm.com              for (uint8_t count = 0; count < 3; count++)
52110802Srene.dejong@arm.com                  scsi_out.message.dataMsg[2 + count] = controlPage[count];
52210802Srene.dejong@arm.com
52310802Srene.dejong@arm.com              scsi_out.msgSize = 20;
52410802Srene.dejong@arm.com              DPRINTF(UFSHostDevice, "CONTROL page\n");
52510802Srene.dejong@arm.com
52610802Srene.dejong@arm.com          } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x01) {//recovery page
52710802Srene.dejong@arm.com              scsi_out.message.dataMsg.resize((sizeof(recoveryPage) >> 2)
52810802Srene.dejong@arm.com                                              + 2);
52910802Srene.dejong@arm.com
53010802Srene.dejong@arm.com              scsi_out.message.dataMsg[0] = 0x00000100;//recovery page code
53110802Srene.dejong@arm.com              scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
53210802Srene.dejong@arm.com
53310802Srene.dejong@arm.com              for (uint8_t count = 0; count < 3; count++)
53410802Srene.dejong@arm.com                  scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
53510802Srene.dejong@arm.com
53610802Srene.dejong@arm.com              scsi_out.msgSize = 20;
53710802Srene.dejong@arm.com              DPRINTF(UFSHostDevice, "RECOVERY page\n");
53810802Srene.dejong@arm.com
53910802Srene.dejong@arm.com          } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x08) {//caching page
54010802Srene.dejong@arm.com
54110802Srene.dejong@arm.com              scsi_out.message.dataMsg.resize((sizeof(cachingPage) >> 2) + 2);
54210802Srene.dejong@arm.com              scsi_out.message.dataMsg[0] = 0x00001200;//caching page code
54310802Srene.dejong@arm.com              scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
54410802Srene.dejong@arm.com
54510802Srene.dejong@arm.com              for (uint8_t count = 0; count < 5; count++)
54610802Srene.dejong@arm.com                  scsi_out.message.dataMsg[2 + count] = cachingPage[count];
54710802Srene.dejong@arm.com
54810802Srene.dejong@arm.com              scsi_out.msgSize = 20;
54910802Srene.dejong@arm.com              DPRINTF(UFSHostDevice, "CACHE page\n");
55010802Srene.dejong@arm.com
55110802Srene.dejong@arm.com          } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x3F) {//ALL the pages!
55210802Srene.dejong@arm.com
55310802Srene.dejong@arm.com              scsi_out.message.dataMsg.resize(((sizeof(controlPage) +
55410802Srene.dejong@arm.com                                                sizeof(recoveryPage) +
55510802Srene.dejong@arm.com                                                sizeof(cachingPage)) >> 2)
55610802Srene.dejong@arm.com                                              + 2);
55710802Srene.dejong@arm.com              scsi_out.message.dataMsg[0] = 0x00003200;//all page code
55810802Srene.dejong@arm.com              scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
55910802Srene.dejong@arm.com
56010802Srene.dejong@arm.com              for (uint8_t count = 0; count < 3; count++)
56110802Srene.dejong@arm.com                  scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
56210802Srene.dejong@arm.com
56310802Srene.dejong@arm.com              for (uint8_t count = 0; count < 5; count++)
56410802Srene.dejong@arm.com                  scsi_out.message.dataMsg[5 + count] = cachingPage[count];
56510802Srene.dejong@arm.com
56610802Srene.dejong@arm.com              for (uint8_t count = 0; count < 3; count++)
56710802Srene.dejong@arm.com                  scsi_out.message.dataMsg[10 + count] = controlPage[count];
56810802Srene.dejong@arm.com
56910802Srene.dejong@arm.com              scsi_out.msgSize = 52;
57010802Srene.dejong@arm.com              DPRINTF(UFSHostDevice, "Return ALL the pages!!!\n");
57110802Srene.dejong@arm.com
57210802Srene.dejong@arm.com          } else inform("Wrong mode page requested\n");
57310802Srene.dejong@arm.com
57410802Srene.dejong@arm.com          scsi_out.message.dataCount = scsi_out.msgSize << 24;
57510802Srene.dejong@arm.com      } break;
57610802Srene.dejong@arm.com
57710802Srene.dejong@arm.com      case SCSIRequestSense: {
57810802Srene.dejong@arm.com          scsi_out.msgSize = 0;
57910802Srene.dejong@arm.com
58010802Srene.dejong@arm.com      } break;
58110802Srene.dejong@arm.com
58210802Srene.dejong@arm.com      case SCSIUnmap:break;//not yet verified
58310802Srene.dejong@arm.com
58410802Srene.dejong@arm.com      case SCSIWriteBuffer: {
58510802Srene.dejong@arm.com          scsi_out.expectMore = 0x01;
58610802Srene.dejong@arm.com
58710802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
58810802Srene.dejong@arm.com
58910802Srene.dejong@arm.com          /**BE and not nicely aligned.*/
59010802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
59110802Srene.dejong@arm.com          uint64_t write_offset = betoh(tmp) & 0xFFFFFF;
59210802Srene.dejong@arm.com
59310802Srene.dejong@arm.com          tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
59410802Srene.dejong@arm.com          uint32_t write_size = betoh(tmp) & 0xFFFFFF;
59510802Srene.dejong@arm.com
59610802Srene.dejong@arm.com          scsi_out.msgSize =  write_size;
59710802Srene.dejong@arm.com          scsi_out.offset = write_offset;
59810802Srene.dejong@arm.com
59910802Srene.dejong@arm.com      } break;
60010802Srene.dejong@arm.com
60110802Srene.dejong@arm.com      case SCSIReadBuffer: {
60210802Srene.dejong@arm.com          /**
60310802Srene.dejong@arm.com           * less trivial than normal read. Size is in bytes instead
60410802Srene.dejong@arm.com           * of blocks, and it is assumed (though not guaranteed) that
60510802Srene.dejong@arm.com           * reading is from cache.
60610802Srene.dejong@arm.com           */
60710802Srene.dejong@arm.com          scsi_out.expectMore = 0x02;
60810802Srene.dejong@arm.com
60910802Srene.dejong@arm.com          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
61010802Srene.dejong@arm.com
61110802Srene.dejong@arm.com          /**BE and not nicely aligned.*/
61210802Srene.dejong@arm.com          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
61310802Srene.dejong@arm.com          uint64_t read_offset = betoh(tmp) & 0xFFFFFF;
61410802Srene.dejong@arm.com
61510802Srene.dejong@arm.com          tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
61610802Srene.dejong@arm.com          uint32_t read_size = betoh(tmp) & 0xFFFFFF;
61710802Srene.dejong@arm.com
61810802Srene.dejong@arm.com          scsi_out.msgSize = read_size;
61910802Srene.dejong@arm.com          scsi_out.offset = read_offset;
62010802Srene.dejong@arm.com
62110802Srene.dejong@arm.com          if ((read_offset + read_size) > capacityLower * blkSize)
62210802Srene.dejong@arm.com              scsi_out.status = SCSIIllegalRequest;
62310802Srene.dejong@arm.com
62410802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Read buffer location: 0x%8x\n",
62510802Srene.dejong@arm.com                  read_offset);
62610802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Number of bytes: 0x%8x\n", read_size);
62710802Srene.dejong@arm.com
62810802Srene.dejong@arm.com          statusCheck(scsi_out.status, scsi_out.senseCode);
62910802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
63010802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
63110802Srene.dejong@arm.com              SCSICheckCondition;
63210802Srene.dejong@arm.com
63310802Srene.dejong@arm.com      } break;
63410802Srene.dejong@arm.com
63510802Srene.dejong@arm.com      case SCSIMaintenanceIn: {
63610802Srene.dejong@arm.com          /**
63710802Srene.dejong@arm.com           * linux sends this command three times from kernel 3.9 onwards,
63810802Srene.dejong@arm.com           * UFS does not support it, nor does this model. Linux knows this,
63910802Srene.dejong@arm.com           * but tries anyway (useful for some SD card types).
64010802Srene.dejong@arm.com           * Lets make clear we don't want it and just ignore it.
64110802Srene.dejong@arm.com           */
64210802Srene.dejong@arm.com          DPRINTF(UFSHostDevice, "Ignoring Maintenance In command\n");
64310802Srene.dejong@arm.com          statusCheck(SCSIIllegalRequest, scsi_out.senseCode);
64410802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
64510802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
64610802Srene.dejong@arm.com              SCSICheckCondition;
64710802Srene.dejong@arm.com          scsi_out.msgSize = 0;
64810802Srene.dejong@arm.com      } break;
64910802Srene.dejong@arm.com
65010802Srene.dejong@arm.com      default: {
65110802Srene.dejong@arm.com          statusCheck(SCSIIllegalRequest, scsi_out.senseCode);
65210802Srene.dejong@arm.com          scsi_out.senseSize = scsi_out.senseCode[0];
65310802Srene.dejong@arm.com          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
65410802Srene.dejong@arm.com              SCSICheckCondition;
65510802Srene.dejong@arm.com          scsi_out.msgSize = 0;
65610802Srene.dejong@arm.com          inform("Unsupported scsi message type: %2x\n", SCSI_msg[4] & 0xFF);
65710802Srene.dejong@arm.com          inform("0x%8x\n", SCSI_msg[0]);
65810802Srene.dejong@arm.com          inform("0x%8x\n", SCSI_msg[1]);
65910802Srene.dejong@arm.com          inform("0x%8x\n", SCSI_msg[2]);
66010802Srene.dejong@arm.com          inform("0x%8x\n", SCSI_msg[3]);
66110802Srene.dejong@arm.com          inform("0x%8x\n", SCSI_msg[4]);
66210802Srene.dejong@arm.com      } break;
66310802Srene.dejong@arm.com    }
66410802Srene.dejong@arm.com
66510802Srene.dejong@arm.com    return scsi_out;
66610802Srene.dejong@arm.com}
66710802Srene.dejong@arm.com
66810802Srene.dejong@arm.com/**
66910802Srene.dejong@arm.com * SCSI status check function. generic device test, creates sense codes
67010802Srene.dejong@arm.com * Future versions may include TODO: device checks, which is why this is
67110802Srene.dejong@arm.com * in a separate function.
67210802Srene.dejong@arm.com */
67310802Srene.dejong@arm.com
67410802Srene.dejong@arm.comvoid
67510802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::statusCheck(uint8_t status,
67610802Srene.dejong@arm.com                                uint8_t* sensecodelist)
67710802Srene.dejong@arm.com{
67810802Srene.dejong@arm.com    for (uint8_t count = 0; count < 19; count++)
67910802Srene.dejong@arm.com        sensecodelist[count] = 0;
68010802Srene.dejong@arm.com
68110802Srene.dejong@arm.com    sensecodelist[0] = 18; //sense length
68210802Srene.dejong@arm.com    sensecodelist[1] = 0x70; //we send a valid frame
68310802Srene.dejong@arm.com    sensecodelist[3] = status & 0xF; //mask to be sure + sensecode
68410802Srene.dejong@arm.com    sensecodelist[8] = 0x1F; //data length
68510802Srene.dejong@arm.com}
68610802Srene.dejong@arm.com
68710802Srene.dejong@arm.com/**
68810802Srene.dejong@arm.com * read from the flashdisk
68910802Srene.dejong@arm.com */
69010802Srene.dejong@arm.com
69110802Srene.dejong@arm.comvoid
69210802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::readFlash(uint8_t* readaddr, uint64_t offset,
69310802Srene.dejong@arm.com                                   uint32_t size)
69410802Srene.dejong@arm.com{
69510802Srene.dejong@arm.com    /** read from image, and get to memory */
69611321Ssteve.reinhardt@amd.com    for (int count = 0; count < (size / SectorSize); count++)
69710802Srene.dejong@arm.com        flashDisk->read(&(readaddr[SectorSize*count]), (offset /
69810802Srene.dejong@arm.com                                                        SectorSize) + count);
69910802Srene.dejong@arm.com}
70010802Srene.dejong@arm.com
70110802Srene.dejong@arm.com/**
70210802Srene.dejong@arm.com * Write to the flashdisk
70310802Srene.dejong@arm.com */
70410802Srene.dejong@arm.com
70510802Srene.dejong@arm.comvoid
70610802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::writeFlash(uint8_t* writeaddr, uint64_t offset,
70710802Srene.dejong@arm.com                                    uint32_t size)
70810802Srene.dejong@arm.com{
70910802Srene.dejong@arm.com    /** Get from fifo and write to image*/
71011321Ssteve.reinhardt@amd.com    for (int count = 0; count < (size / SectorSize); count++)
71110802Srene.dejong@arm.com        flashDisk->write(&(writeaddr[SectorSize * count]),
71210802Srene.dejong@arm.com                         (offset / SectorSize) + count);
71310802Srene.dejong@arm.com}
71410802Srene.dejong@arm.com
71510802Srene.dejong@arm.com/**
71610802Srene.dejong@arm.com * Constructor for the UFS Host device
71710802Srene.dejong@arm.com */
71810802Srene.dejong@arm.com
71910802Srene.dejong@arm.comUFSHostDevice::UFSHostDevice(const UFSHostDeviceParams* p) :
72010802Srene.dejong@arm.com    DmaDevice(p),
72110802Srene.dejong@arm.com    pioAddr(p->pio_addr),
72210802Srene.dejong@arm.com    pioSize(0x0FFF),
72310802Srene.dejong@arm.com    pioDelay(p->pio_latency),
72410802Srene.dejong@arm.com    intNum(p->int_num),
72510802Srene.dejong@arm.com    gic(p->gic),
72610802Srene.dejong@arm.com    lunAvail(p->image.size()),
72710802Srene.dejong@arm.com    UFSSlots(p->ufs_slots - 1),
72810802Srene.dejong@arm.com    readPendingNum(0),
72910802Srene.dejong@arm.com    writePendingNum(0),
73010802Srene.dejong@arm.com    activeDoorbells(0),
73110802Srene.dejong@arm.com    pendingDoorbells(0),
73210802Srene.dejong@arm.com    countInt(0),
73310802Srene.dejong@arm.com    transferTrack(0),
73410802Srene.dejong@arm.com    taskCommandTrack(0),
73510802Srene.dejong@arm.com    idlePhaseStart(0),
73612087Sspwilson2@wisc.edu    SCSIResumeEvent([this]{ SCSIStart(); }, name()),
73712087Sspwilson2@wisc.edu    UTPEvent([this]{ finalUTP(); }, name())
73810802Srene.dejong@arm.com{
73910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "The hostcontroller hosts %d Logic units\n",
74010802Srene.dejong@arm.com            lunAvail);
74110802Srene.dejong@arm.com    UFSDevice.resize(lunAvail);
74210802Srene.dejong@arm.com
74310802Srene.dejong@arm.com    transferDoneCallback = new MakeCallback<UFSHostDevice,
74410802Srene.dejong@arm.com        &UFSHostDevice::LUNSignal>(this);
74510802Srene.dejong@arm.com    memReadCallback = new MakeCallback<UFSHostDevice,
74610802Srene.dejong@arm.com        &UFSHostDevice::readCallback>(this);
74710802Srene.dejong@arm.com
74811321Ssteve.reinhardt@amd.com    for (int count = 0; count < lunAvail; count++) {
74910802Srene.dejong@arm.com        UFSDevice[count] = new UFSSCSIDevice(p, count, transferDoneCallback,
75010802Srene.dejong@arm.com                                             memReadCallback);
75110802Srene.dejong@arm.com    }
75210802Srene.dejong@arm.com
75310802Srene.dejong@arm.com    if (UFSSlots > 31)
75410802Srene.dejong@arm.com        warn("UFSSlots = %d, this will results in %d command slots",
75510802Srene.dejong@arm.com             UFSSlots, (UFSSlots & 0x1F));
75610802Srene.dejong@arm.com
75710802Srene.dejong@arm.com    if ((UFSSlots & 0x1F) == 0)
75810802Srene.dejong@arm.com        fatal("Number of UFS command slots should be between 1 and 32.");
75910802Srene.dejong@arm.com
76010802Srene.dejong@arm.com    setValues();
76110802Srene.dejong@arm.com}
76210802Srene.dejong@arm.com
76310802Srene.dejong@arm.com/**
76410802Srene.dejong@arm.com * Create the parameters of this device
76510802Srene.dejong@arm.com */
76610802Srene.dejong@arm.com
76710802Srene.dejong@arm.comUFSHostDevice*
76810802Srene.dejong@arm.comUFSHostDeviceParams::create()
76910802Srene.dejong@arm.com{
77010802Srene.dejong@arm.com    return new UFSHostDevice(this);
77110802Srene.dejong@arm.com}
77210802Srene.dejong@arm.com
77310802Srene.dejong@arm.com
77410802Srene.dejong@arm.comvoid
77510802Srene.dejong@arm.comUFSHostDevice::regStats()
77610802Srene.dejong@arm.com{
77711523Sdavid.guillen@arm.com    DmaDevice::regStats();
77811523Sdavid.guillen@arm.com
77910802Srene.dejong@arm.com    using namespace Stats;
78010802Srene.dejong@arm.com
78110802Srene.dejong@arm.com    std::string UFSHost_name = name() + ".UFSDiskHost";
78210802Srene.dejong@arm.com
78310802Srene.dejong@arm.com    // Register the stats
78410802Srene.dejong@arm.com    /** Queue lengths */
78510802Srene.dejong@arm.com    stats.currentSCSIQueue
78610802Srene.dejong@arm.com        .name(UFSHost_name + ".currentSCSIQueue")
78710802Srene.dejong@arm.com        .desc("Most up to date length of the command queue")
78810802Srene.dejong@arm.com        .flags(none);
78910802Srene.dejong@arm.com    stats.currentReadSSDQueue
79010802Srene.dejong@arm.com        .name(UFSHost_name + ".currentReadSSDQueue")
79110802Srene.dejong@arm.com        .desc("Most up to date length of the read SSD queue")
79210802Srene.dejong@arm.com        .flags(none);
79310802Srene.dejong@arm.com    stats.currentWriteSSDQueue
79410802Srene.dejong@arm.com        .name(UFSHost_name + ".currentWriteSSDQueue")
79510802Srene.dejong@arm.com        .desc("Most up to date length of the write SSD queue")
79610802Srene.dejong@arm.com        .flags(none);
79710802Srene.dejong@arm.com
79810802Srene.dejong@arm.com    /** Amount of data read/written */
79910802Srene.dejong@arm.com    stats.totalReadSSD
80010802Srene.dejong@arm.com        .name(UFSHost_name + ".totalReadSSD")
80110802Srene.dejong@arm.com        .desc("Number of bytes read from SSD")
80210802Srene.dejong@arm.com        .flags(none);
80310802Srene.dejong@arm.com
80410802Srene.dejong@arm.com    stats.totalWrittenSSD
80510802Srene.dejong@arm.com        .name(UFSHost_name + ".totalWrittenSSD")
80610802Srene.dejong@arm.com        .desc("Number of bytes written to SSD")
80710802Srene.dejong@arm.com        .flags(none);
80810802Srene.dejong@arm.com
80910802Srene.dejong@arm.com    stats.totalReadDiskTransactions
81010802Srene.dejong@arm.com        .name(UFSHost_name + ".totalReadDiskTransactions")
81110802Srene.dejong@arm.com        .desc("Number of transactions from disk")
81210802Srene.dejong@arm.com        .flags(none);
81310802Srene.dejong@arm.com    stats.totalWriteDiskTransactions
81410802Srene.dejong@arm.com        .name(UFSHost_name + ".totalWriteDiskTransactions")
81510802Srene.dejong@arm.com        .desc("Number of transactions to disk")
81610802Srene.dejong@arm.com        .flags(none);
81710802Srene.dejong@arm.com    stats.totalReadUFSTransactions
81810802Srene.dejong@arm.com        .name(UFSHost_name + ".totalReadUFSTransactions")
81910802Srene.dejong@arm.com        .desc("Number of transactions from device")
82010802Srene.dejong@arm.com        .flags(none);
82110802Srene.dejong@arm.com    stats.totalWriteUFSTransactions
82210802Srene.dejong@arm.com        .name(UFSHost_name + ".totalWriteUFSTransactions")
82310802Srene.dejong@arm.com        .desc("Number of transactions to device")
82410802Srene.dejong@arm.com        .flags(none);
82510802Srene.dejong@arm.com
82610802Srene.dejong@arm.com    /** Average bandwidth for reads and writes */
82710802Srene.dejong@arm.com    stats.averageReadSSDBW
82810802Srene.dejong@arm.com        .name(UFSHost_name + ".averageReadSSDBandwidth")
82910802Srene.dejong@arm.com        .desc("Average read bandwidth (bytes/s)")
83010802Srene.dejong@arm.com        .flags(nozero);
83110802Srene.dejong@arm.com
83210802Srene.dejong@arm.com    stats.averageReadSSDBW = stats.totalReadSSD / simSeconds;
83310802Srene.dejong@arm.com
83410802Srene.dejong@arm.com    stats.averageWriteSSDBW
83510802Srene.dejong@arm.com        .name(UFSHost_name + ".averageWriteSSDBandwidth")
83610802Srene.dejong@arm.com        .desc("Average write bandwidth (bytes/s)")
83710802Srene.dejong@arm.com        .flags(nozero);
83810802Srene.dejong@arm.com
83910802Srene.dejong@arm.com    stats.averageWriteSSDBW = stats.totalWrittenSSD / simSeconds;
84010802Srene.dejong@arm.com
84110802Srene.dejong@arm.com    stats.averageSCSIQueue
84210802Srene.dejong@arm.com        .name(UFSHost_name + ".averageSCSIQueueLength")
84310802Srene.dejong@arm.com        .desc("Average command queue length")
84410802Srene.dejong@arm.com        .flags(nozero);
84510802Srene.dejong@arm.com    stats.averageReadSSDQueue
84610802Srene.dejong@arm.com        .name(UFSHost_name + ".averageReadSSDQueueLength")
84710802Srene.dejong@arm.com        .desc("Average read queue length")
84810802Srene.dejong@arm.com        .flags(nozero);
84910802Srene.dejong@arm.com    stats.averageWriteSSDQueue
85010802Srene.dejong@arm.com        .name(UFSHost_name + ".averageWriteSSDQueueLength")
85110802Srene.dejong@arm.com        .desc("Average write queue length")
85210802Srene.dejong@arm.com        .flags(nozero);
85310802Srene.dejong@arm.com
85410802Srene.dejong@arm.com    /** Number of doorbells rung*/
85510802Srene.dejong@arm.com    stats.curDoorbell
85610802Srene.dejong@arm.com        .name(UFSHost_name + ".curDoorbell")
85710802Srene.dejong@arm.com        .desc("Most up to date number of doorbells used")
85810802Srene.dejong@arm.com        .flags(none);
85910802Srene.dejong@arm.com
86010802Srene.dejong@arm.com    stats.curDoorbell = activeDoorbells;
86110802Srene.dejong@arm.com
86210802Srene.dejong@arm.com    stats.maxDoorbell
86310802Srene.dejong@arm.com        .name(UFSHost_name + ".maxDoorbell")
86410802Srene.dejong@arm.com        .desc("Maximum number of doorbells utilized")
86510802Srene.dejong@arm.com        .flags(none);
86610802Srene.dejong@arm.com    stats.averageDoorbell
86710802Srene.dejong@arm.com        .name(UFSHost_name + ".averageDoorbell")
86810802Srene.dejong@arm.com        .desc("Average number of Doorbells used")
86910802Srene.dejong@arm.com        .flags(nozero);
87010802Srene.dejong@arm.com
87110802Srene.dejong@arm.com    /** Latency*/
87210802Srene.dejong@arm.com    stats.transactionLatency
87310802Srene.dejong@arm.com        .init(100)
87410802Srene.dejong@arm.com        .name(UFSHost_name + ".transactionLatency")
87510802Srene.dejong@arm.com        .desc("Histogram of transaction times")
87610802Srene.dejong@arm.com        .flags(pdf);
87710802Srene.dejong@arm.com
87810802Srene.dejong@arm.com    stats.idleTimes
87910802Srene.dejong@arm.com        .init(100)
88010802Srene.dejong@arm.com        .name(UFSHost_name + ".idlePeriods")
88110802Srene.dejong@arm.com        .desc("Histogram of idle times")
88210802Srene.dejong@arm.com        .flags(pdf);
88310802Srene.dejong@arm.com
88410802Srene.dejong@arm.com}
88510802Srene.dejong@arm.com
88610802Srene.dejong@arm.com/**
88710802Srene.dejong@arm.com * Register init
88810802Srene.dejong@arm.com */
88910802Srene.dejong@arm.comvoid UFSHostDevice::setValues()
89010802Srene.dejong@arm.com{
89110802Srene.dejong@arm.com    /**
89210802Srene.dejong@arm.com     * The capability register is built up as follows:
89310802Srene.dejong@arm.com     * 31-29 RES; Testmode support; O3 delivery; 64 bit addr;
89410802Srene.dejong@arm.com     * 23-19 RES; 18-16 #TM Req slots; 15-5 RES;4-0 # TR slots
89510802Srene.dejong@arm.com     */
89610802Srene.dejong@arm.com    UFSHCIMem.HCCAP = 0x06070000 | (UFSSlots & 0x1F);
89710802Srene.dejong@arm.com    UFSHCIMem.HCversion = 0x00010000; //version is 1.0
89810802Srene.dejong@arm.com    UFSHCIMem.HCHCDDID = 0xAA003C3C;// Arbitrary number
89910802Srene.dejong@arm.com    UFSHCIMem.HCHCPMID = 0x41524D48; //ARMH (not an official MIPI number)
90010802Srene.dejong@arm.com    UFSHCIMem.TRUTRLDBR = 0x00;
90110802Srene.dejong@arm.com    UFSHCIMem.TMUTMRLDBR = 0x00;
90210802Srene.dejong@arm.com    UFSHCIMem.CMDUICCMDR = 0x00;
90310802Srene.dejong@arm.com    // We can process CMD, TM, TR, device present
90410802Srene.dejong@arm.com    UFSHCIMem.ORHostControllerStatus = 0x08;
90510802Srene.dejong@arm.com    UFSHCIMem.TRUTRLBA = 0x00;
90610802Srene.dejong@arm.com    UFSHCIMem.TRUTRLBAU = 0x00;
90710802Srene.dejong@arm.com    UFSHCIMem.TMUTMRLBA = 0x00;
90810802Srene.dejong@arm.com    UFSHCIMem.TMUTMRLBAU = 0x00;
90910802Srene.dejong@arm.com}
91010802Srene.dejong@arm.com
91110802Srene.dejong@arm.com/**
91210802Srene.dejong@arm.com * Determine address ranges
91310802Srene.dejong@arm.com */
91410802Srene.dejong@arm.com
91510802Srene.dejong@arm.comAddrRangeList
91610802Srene.dejong@arm.comUFSHostDevice::getAddrRanges() const
91710802Srene.dejong@arm.com{
91810802Srene.dejong@arm.com    AddrRangeList ranges;
91910802Srene.dejong@arm.com    ranges.push_back(RangeSize(pioAddr, pioSize));
92010802Srene.dejong@arm.com    return ranges;
92110802Srene.dejong@arm.com}
92210802Srene.dejong@arm.com
92310802Srene.dejong@arm.com/**
92410802Srene.dejong@arm.com * UFSHCD read register. This function allows the system to read the
92510802Srene.dejong@arm.com * register entries
92610802Srene.dejong@arm.com */
92710802Srene.dejong@arm.com
92810802Srene.dejong@arm.comTick
92910802Srene.dejong@arm.comUFSHostDevice::read(PacketPtr pkt)
93010802Srene.dejong@arm.com{
93110802Srene.dejong@arm.com    uint32_t data = 0;
93210802Srene.dejong@arm.com
93310802Srene.dejong@arm.com    switch (pkt->getAddr() & 0xFF)
93410802Srene.dejong@arm.com    {
93510802Srene.dejong@arm.com
93610802Srene.dejong@arm.com      case regControllerCapabilities:
93710802Srene.dejong@arm.com        data = UFSHCIMem.HCCAP;
93810802Srene.dejong@arm.com        break;
93910802Srene.dejong@arm.com
94010802Srene.dejong@arm.com      case regUFSVersion:
94110802Srene.dejong@arm.com        data = UFSHCIMem.HCversion;
94210802Srene.dejong@arm.com        break;
94310802Srene.dejong@arm.com
94410802Srene.dejong@arm.com      case regControllerDEVID:
94510802Srene.dejong@arm.com        data = UFSHCIMem.HCHCDDID;
94610802Srene.dejong@arm.com        break;
94710802Srene.dejong@arm.com
94810802Srene.dejong@arm.com      case regControllerPRODID:
94910802Srene.dejong@arm.com        data = UFSHCIMem.HCHCPMID;
95010802Srene.dejong@arm.com        break;
95110802Srene.dejong@arm.com
95210802Srene.dejong@arm.com      case regInterruptStatus:
95310802Srene.dejong@arm.com        data = UFSHCIMem.ORInterruptStatus;
95410802Srene.dejong@arm.com        UFSHCIMem.ORInterruptStatus = 0x00;
95510802Srene.dejong@arm.com        //TODO: Revise and extend
95610802Srene.dejong@arm.com        clearInterrupt();
95710802Srene.dejong@arm.com        break;
95810802Srene.dejong@arm.com
95910802Srene.dejong@arm.com      case regInterruptEnable:
96010802Srene.dejong@arm.com        data = UFSHCIMem.ORInterruptEnable;
96110802Srene.dejong@arm.com        break;
96210802Srene.dejong@arm.com
96310802Srene.dejong@arm.com      case regControllerStatus:
96410802Srene.dejong@arm.com        data = UFSHCIMem.ORHostControllerStatus;
96510802Srene.dejong@arm.com        break;
96610802Srene.dejong@arm.com
96710802Srene.dejong@arm.com      case regControllerEnable:
96810802Srene.dejong@arm.com        data = UFSHCIMem.ORHostControllerEnable;
96910802Srene.dejong@arm.com        break;
97010802Srene.dejong@arm.com
97110802Srene.dejong@arm.com      case regUICErrorCodePHYAdapterLayer:
97210802Srene.dejong@arm.com        data = UFSHCIMem.ORUECPA;
97310802Srene.dejong@arm.com        break;
97410802Srene.dejong@arm.com
97510802Srene.dejong@arm.com      case regUICErrorCodeDataLinkLayer:
97610802Srene.dejong@arm.com        data = UFSHCIMem.ORUECDL;
97710802Srene.dejong@arm.com        break;
97810802Srene.dejong@arm.com
97910802Srene.dejong@arm.com      case regUICErrorCodeNetworkLayer:
98010802Srene.dejong@arm.com        data = UFSHCIMem.ORUECN;
98110802Srene.dejong@arm.com        break;
98210802Srene.dejong@arm.com
98310802Srene.dejong@arm.com      case regUICErrorCodeTransportLayer:
98410802Srene.dejong@arm.com        data = UFSHCIMem.ORUECT;
98510802Srene.dejong@arm.com        break;
98610802Srene.dejong@arm.com
98710802Srene.dejong@arm.com      case regUICErrorCodeDME:
98810802Srene.dejong@arm.com        data = UFSHCIMem.ORUECDME;
98910802Srene.dejong@arm.com        break;
99010802Srene.dejong@arm.com
99110802Srene.dejong@arm.com      case regUTPTransferREQINTAGGControl:
99210802Srene.dejong@arm.com        data = UFSHCIMem.ORUTRIACR;
99310802Srene.dejong@arm.com        break;
99410802Srene.dejong@arm.com
99510802Srene.dejong@arm.com      case regUTPTransferREQListBaseL:
99610802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLBA;
99710802Srene.dejong@arm.com        break;
99810802Srene.dejong@arm.com
99910802Srene.dejong@arm.com      case regUTPTransferREQListBaseH:
100010802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLBAU;
100110802Srene.dejong@arm.com        break;
100210802Srene.dejong@arm.com
100310802Srene.dejong@arm.com      case regUTPTransferREQDoorbell:
100410802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLDBR;
100510802Srene.dejong@arm.com        break;
100610802Srene.dejong@arm.com
100710802Srene.dejong@arm.com      case regUTPTransferREQListClear:
100810802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLCLR;
100910802Srene.dejong@arm.com        break;
101010802Srene.dejong@arm.com
101110802Srene.dejong@arm.com      case regUTPTransferREQListRunStop:
101210802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLRSR;
101310802Srene.dejong@arm.com        break;
101410802Srene.dejong@arm.com
101510802Srene.dejong@arm.com      case regUTPTaskREQListBaseL:
101610802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLBA;
101710802Srene.dejong@arm.com        break;
101810802Srene.dejong@arm.com
101910802Srene.dejong@arm.com      case regUTPTaskREQListBaseH:
102010802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLBAU;
102110802Srene.dejong@arm.com        break;
102210802Srene.dejong@arm.com
102310802Srene.dejong@arm.com      case regUTPTaskREQDoorbell:
102410802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLDBR;
102510802Srene.dejong@arm.com        break;
102610802Srene.dejong@arm.com
102710802Srene.dejong@arm.com      case regUTPTaskREQListClear:
102810802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLCLR;
102910802Srene.dejong@arm.com        break;
103010802Srene.dejong@arm.com
103110802Srene.dejong@arm.com      case regUTPTaskREQListRunStop:
103210802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLRSR;
103310802Srene.dejong@arm.com        break;
103410802Srene.dejong@arm.com
103510802Srene.dejong@arm.com      case regUICCommand:
103610802Srene.dejong@arm.com        data = UFSHCIMem.CMDUICCMDR;
103710802Srene.dejong@arm.com        break;
103810802Srene.dejong@arm.com
103910802Srene.dejong@arm.com      case regUICCommandArg1:
104010802Srene.dejong@arm.com        data = UFSHCIMem.CMDUCMDARG1;
104110802Srene.dejong@arm.com        break;
104210802Srene.dejong@arm.com
104310802Srene.dejong@arm.com      case regUICCommandArg2:
104410802Srene.dejong@arm.com        data = UFSHCIMem.CMDUCMDARG2;
104510802Srene.dejong@arm.com        break;
104610802Srene.dejong@arm.com
104710802Srene.dejong@arm.com      case regUICCommandArg3:
104810802Srene.dejong@arm.com        data = UFSHCIMem.CMDUCMDARG3;
104910802Srene.dejong@arm.com        break;
105010802Srene.dejong@arm.com
105110802Srene.dejong@arm.com      default:
105210802Srene.dejong@arm.com        data = 0x00;
105310802Srene.dejong@arm.com        break;
105410802Srene.dejong@arm.com    }
105510802Srene.dejong@arm.com
105613230Sgabeblack@google.com    pkt->setLE<uint32_t>(data);
105710802Srene.dejong@arm.com    pkt->makeResponse();
105810802Srene.dejong@arm.com    return pioDelay;
105910802Srene.dejong@arm.com}
106010802Srene.dejong@arm.com
106110802Srene.dejong@arm.com/**
106210802Srene.dejong@arm.com * UFSHCD write function. This function allows access to the writeable
106310802Srene.dejong@arm.com * registers. If any function attempts to write value to an unwriteable
106410802Srene.dejong@arm.com * register entry, then the value will not be written.
106510802Srene.dejong@arm.com */
106610802Srene.dejong@arm.comTick
106710802Srene.dejong@arm.comUFSHostDevice::write(PacketPtr pkt)
106810802Srene.dejong@arm.com{
106910802Srene.dejong@arm.com    uint32_t data = 0;
107010802Srene.dejong@arm.com
107110802Srene.dejong@arm.com    switch (pkt->getSize()) {
107210802Srene.dejong@arm.com
107310802Srene.dejong@arm.com      case 1:
107413230Sgabeblack@google.com        data = pkt->getLE<uint8_t>();
107510802Srene.dejong@arm.com        break;
107610802Srene.dejong@arm.com
107710802Srene.dejong@arm.com      case 2:
107813230Sgabeblack@google.com        data = pkt->getLE<uint16_t>();
107910802Srene.dejong@arm.com        break;
108010802Srene.dejong@arm.com
108110802Srene.dejong@arm.com      case 4:
108213230Sgabeblack@google.com        data = pkt->getLE<uint32_t>();
108310802Srene.dejong@arm.com        break;
108410802Srene.dejong@arm.com
108510802Srene.dejong@arm.com      default:
108610802Srene.dejong@arm.com        panic("Undefined UFSHCD controller write size!\n");
108710802Srene.dejong@arm.com        break;
108810802Srene.dejong@arm.com    }
108910802Srene.dejong@arm.com
109010802Srene.dejong@arm.com    switch (pkt->getAddr() & 0xFF)
109110802Srene.dejong@arm.com    {
109210802Srene.dejong@arm.com      case regControllerCapabilities://you shall not write to this
109310802Srene.dejong@arm.com        break;
109410802Srene.dejong@arm.com
109510802Srene.dejong@arm.com      case regUFSVersion://you shall not write to this
109610802Srene.dejong@arm.com        break;
109710802Srene.dejong@arm.com
109810802Srene.dejong@arm.com      case regControllerDEVID://you shall not write to this
109910802Srene.dejong@arm.com        break;
110010802Srene.dejong@arm.com
110110802Srene.dejong@arm.com      case regControllerPRODID://you shall not write to this
110210802Srene.dejong@arm.com        break;
110310802Srene.dejong@arm.com
110410802Srene.dejong@arm.com      case regInterruptStatus://you shall not write to this
110510802Srene.dejong@arm.com        break;
110610802Srene.dejong@arm.com
110710802Srene.dejong@arm.com      case regInterruptEnable:
110810802Srene.dejong@arm.com        UFSHCIMem.ORInterruptEnable = data;
110910802Srene.dejong@arm.com        break;
111010802Srene.dejong@arm.com
111110802Srene.dejong@arm.com      case regControllerStatus:
111210802Srene.dejong@arm.com        UFSHCIMem.ORHostControllerStatus = data;
111310802Srene.dejong@arm.com        break;
111410802Srene.dejong@arm.com
111510802Srene.dejong@arm.com      case regControllerEnable:
111610802Srene.dejong@arm.com        UFSHCIMem.ORHostControllerEnable = data;
111710802Srene.dejong@arm.com        break;
111810802Srene.dejong@arm.com
111910802Srene.dejong@arm.com      case regUICErrorCodePHYAdapterLayer:
112010802Srene.dejong@arm.com        UFSHCIMem.ORUECPA = data;
112110802Srene.dejong@arm.com        break;
112210802Srene.dejong@arm.com
112310802Srene.dejong@arm.com      case regUICErrorCodeDataLinkLayer:
112410802Srene.dejong@arm.com        UFSHCIMem.ORUECDL = data;
112510802Srene.dejong@arm.com        break;
112610802Srene.dejong@arm.com
112710802Srene.dejong@arm.com      case regUICErrorCodeNetworkLayer:
112810802Srene.dejong@arm.com        UFSHCIMem.ORUECN = data;
112910802Srene.dejong@arm.com        break;
113010802Srene.dejong@arm.com
113110802Srene.dejong@arm.com      case regUICErrorCodeTransportLayer:
113210802Srene.dejong@arm.com        UFSHCIMem.ORUECT = data;
113310802Srene.dejong@arm.com        break;
113410802Srene.dejong@arm.com
113510802Srene.dejong@arm.com      case regUICErrorCodeDME:
113610802Srene.dejong@arm.com        UFSHCIMem.ORUECDME = data;
113710802Srene.dejong@arm.com        break;
113810802Srene.dejong@arm.com
113910802Srene.dejong@arm.com      case regUTPTransferREQINTAGGControl:
114010802Srene.dejong@arm.com        UFSHCIMem.ORUTRIACR = data;
114110802Srene.dejong@arm.com        break;
114210802Srene.dejong@arm.com
114310802Srene.dejong@arm.com      case regUTPTransferREQListBaseL:
114410802Srene.dejong@arm.com        UFSHCIMem.TRUTRLBA = data;
114510802Srene.dejong@arm.com        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
114610802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU)!= 0x00))
114710802Srene.dejong@arm.com            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
114810802Srene.dejong@arm.com        break;
114910802Srene.dejong@arm.com
115010802Srene.dejong@arm.com      case regUTPTransferREQListBaseH:
115110802Srene.dejong@arm.com        UFSHCIMem.TRUTRLBAU = data;
115210802Srene.dejong@arm.com        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
115310802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
115410802Srene.dejong@arm.com            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
115510802Srene.dejong@arm.com        break;
115610802Srene.dejong@arm.com
115710802Srene.dejong@arm.com      case regUTPTransferREQDoorbell:
115810802Srene.dejong@arm.com        if (!(UFSHCIMem.TRUTRLDBR) && data)
115910802Srene.dejong@arm.com            stats.idleTimes.sample(curTick() - idlePhaseStart);
116010802Srene.dejong@arm.com        UFSHCIMem.TRUTRLDBR |= data;
116110802Srene.dejong@arm.com        requestHandler();
116210802Srene.dejong@arm.com        break;
116310802Srene.dejong@arm.com
116410802Srene.dejong@arm.com      case regUTPTransferREQListClear:
116510802Srene.dejong@arm.com        UFSHCIMem.TRUTRLCLR = data;
116610802Srene.dejong@arm.com        break;
116710802Srene.dejong@arm.com
116810802Srene.dejong@arm.com      case regUTPTransferREQListRunStop:
116910802Srene.dejong@arm.com        UFSHCIMem.TRUTRLRSR = data;
117010802Srene.dejong@arm.com        break;
117110802Srene.dejong@arm.com
117210802Srene.dejong@arm.com      case regUTPTaskREQListBaseL:
117310802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLBA = data;
117410802Srene.dejong@arm.com        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
117510802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
117610802Srene.dejong@arm.com            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
117710802Srene.dejong@arm.com        break;
117810802Srene.dejong@arm.com
117910802Srene.dejong@arm.com      case regUTPTaskREQListBaseH:
118010802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLBAU = data;
118110802Srene.dejong@arm.com        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
118210802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
118310802Srene.dejong@arm.com            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
118410802Srene.dejong@arm.com        break;
118510802Srene.dejong@arm.com
118610802Srene.dejong@arm.com      case regUTPTaskREQDoorbell:
118710802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLDBR |= data;
118810802Srene.dejong@arm.com        requestHandler();
118910802Srene.dejong@arm.com        break;
119010802Srene.dejong@arm.com
119110802Srene.dejong@arm.com      case regUTPTaskREQListClear:
119210802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLCLR = data;
119310802Srene.dejong@arm.com        break;
119410802Srene.dejong@arm.com
119510802Srene.dejong@arm.com      case regUTPTaskREQListRunStop:
119610802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLRSR = data;
119710802Srene.dejong@arm.com        break;
119810802Srene.dejong@arm.com
119910802Srene.dejong@arm.com      case regUICCommand:
120010802Srene.dejong@arm.com        UFSHCIMem.CMDUICCMDR = data;
120110802Srene.dejong@arm.com        requestHandler();
120210802Srene.dejong@arm.com        break;
120310802Srene.dejong@arm.com
120410802Srene.dejong@arm.com      case regUICCommandArg1:
120510802Srene.dejong@arm.com        UFSHCIMem.CMDUCMDARG1 = data;
120610802Srene.dejong@arm.com        break;
120710802Srene.dejong@arm.com
120810802Srene.dejong@arm.com      case regUICCommandArg2:
120910802Srene.dejong@arm.com        UFSHCIMem.CMDUCMDARG2 = data;
121010802Srene.dejong@arm.com        break;
121110802Srene.dejong@arm.com
121210802Srene.dejong@arm.com      case regUICCommandArg3:
121310802Srene.dejong@arm.com        UFSHCIMem.CMDUCMDARG3 = data;
121410802Srene.dejong@arm.com        break;
121510802Srene.dejong@arm.com
121610802Srene.dejong@arm.com      default:break;//nothing happens, you try to access a register that
121710802Srene.dejong@arm.com                    //does not exist
121810802Srene.dejong@arm.com
121910802Srene.dejong@arm.com    }
122010802Srene.dejong@arm.com
122110802Srene.dejong@arm.com    pkt->makeResponse();
122210802Srene.dejong@arm.com    return pioDelay;
122310802Srene.dejong@arm.com}
122410802Srene.dejong@arm.com
122510802Srene.dejong@arm.com/**
122610802Srene.dejong@arm.com * Request handler. Determines where the request comes from and initiates the
122710802Srene.dejong@arm.com * appropriate actions accordingly.
122810802Srene.dejong@arm.com */
122910802Srene.dejong@arm.com
123010802Srene.dejong@arm.comvoid
123110802Srene.dejong@arm.comUFSHostDevice::requestHandler()
123210802Srene.dejong@arm.com{
123310802Srene.dejong@arm.com    Addr address = 0x00;
123410802Srene.dejong@arm.com    int mask = 0x01;
123510802Srene.dejong@arm.com    int size;
123610802Srene.dejong@arm.com    int count = 0;
123710802Srene.dejong@arm.com    struct taskStart task_info;
123810802Srene.dejong@arm.com    struct transferStart transferstart_info;
123910802Srene.dejong@arm.com    transferstart_info.done = 0;
124010802Srene.dejong@arm.com
124110802Srene.dejong@arm.com    /**
124210802Srene.dejong@arm.com     * step1 determine what called us
124310802Srene.dejong@arm.com     * step2 determine where to get it
124410802Srene.dejong@arm.com     * Look for any request of which we where not yet aware
124510802Srene.dejong@arm.com     */
124610802Srene.dejong@arm.com    while (((UFSHCIMem.CMDUICCMDR > 0x00) |
124710802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) |
124810802Srene.dejong@arm.com            ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00)) ) {
124910802Srene.dejong@arm.com
125010802Srene.dejong@arm.com        if (UFSHCIMem.CMDUICCMDR > 0x00) {
125110802Srene.dejong@arm.com            /**
125210802Srene.dejong@arm.com             * Command; general control of the Host controller.
125310802Srene.dejong@arm.com             * no DMA transfer needed
125410802Srene.dejong@arm.com             */
125510802Srene.dejong@arm.com            commandHandler();
125610802Srene.dejong@arm.com            UFSHCIMem.ORInterruptStatus |= UICCommandCOMPL;
125710802Srene.dejong@arm.com            generateInterrupt();
125810802Srene.dejong@arm.com            UFSHCIMem.CMDUICCMDR = 0x00;
125910802Srene.dejong@arm.com            return; //command, nothing more we can do
126010802Srene.dejong@arm.com
126110802Srene.dejong@arm.com        } else if ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) {
126210802Srene.dejong@arm.com            /**
126310802Srene.dejong@arm.com             * Task; flow control, meant for the device/Logic unit
126410802Srene.dejong@arm.com             * DMA transfer is needed, flash will not be approached
126510802Srene.dejong@arm.com             */
126610802Srene.dejong@arm.com            size = sizeof(UTPUPIUTaskReq);
126710802Srene.dejong@arm.com            /**Find the position that is not handled yet*/
126810802Srene.dejong@arm.com            count = findLsbSet((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack));
126910802Srene.dejong@arm.com            address = UFSHCIMem.TMUTMRLBAU;
127010802Srene.dejong@arm.com            //<-64 bit
127110802Srene.dejong@arm.com            address = (count * size) + (address << 32) +
127210802Srene.dejong@arm.com                UFSHCIMem.TMUTMRLBA;
127310802Srene.dejong@arm.com            taskCommandTrack |= mask << count;
127410802Srene.dejong@arm.com
127510802Srene.dejong@arm.com            inform("UFSmodel received a task from the system; this might"
127610802Srene.dejong@arm.com                   " lead to untested behaviour.\n");
127710802Srene.dejong@arm.com
127810802Srene.dejong@arm.com            task_info.mask = mask << count;
127910802Srene.dejong@arm.com            task_info.address = address;
128010802Srene.dejong@arm.com            task_info.size = size;
128110802Srene.dejong@arm.com            task_info.done = UFSHCIMem.TMUTMRLDBR;
128210802Srene.dejong@arm.com            taskInfo.push_back(task_info);
128312087Sspwilson2@wisc.edu            taskEventQueue.push_back(
128412087Sspwilson2@wisc.edu                EventFunctionWrapper([this]{ taskStart(); }, name()));
128510802Srene.dejong@arm.com            writeDevice(&taskEventQueue.back(), false, address, size,
128610802Srene.dejong@arm.com                        reinterpret_cast<uint8_t*>
128710802Srene.dejong@arm.com                        (&taskInfo.back().destination), 0, 0);
128810802Srene.dejong@arm.com
128910802Srene.dejong@arm.com        } else if ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00) {
129010802Srene.dejong@arm.com            /**
129110802Srene.dejong@arm.com             * Transfer; Data transfer from or to the disk. There will be DMA
129210802Srene.dejong@arm.com             * transfers, and the flash might be approached. Further
129310802Srene.dejong@arm.com             * commands, are needed to specify the exact command.
129410802Srene.dejong@arm.com             */
129510802Srene.dejong@arm.com            size = sizeof(UTPTransferReqDesc);
129610802Srene.dejong@arm.com            /**Find the position that is not handled yet*/
129710802Srene.dejong@arm.com            count = findLsbSet((UFSHCIMem.TRUTRLDBR ^ transferTrack));
129810802Srene.dejong@arm.com            address = UFSHCIMem.TRUTRLBAU;
129910802Srene.dejong@arm.com            //<-64 bit
130010802Srene.dejong@arm.com            address = (count * size) + (address << 32) + UFSHCIMem.TRUTRLBA;
130110802Srene.dejong@arm.com
130210802Srene.dejong@arm.com            transferTrack |= mask << count;
130310802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Doorbell register: 0x%8x select #:"
130410802Srene.dejong@arm.com                    " 0x%8x completion info: 0x%8x\n", UFSHCIMem.TRUTRLDBR,
130510802Srene.dejong@arm.com                    count, transferstart_info.done);
130610802Srene.dejong@arm.com
130710802Srene.dejong@arm.com            transferstart_info.done = UFSHCIMem.TRUTRLDBR;
130810802Srene.dejong@arm.com
130910802Srene.dejong@arm.com            /**stats**/
131010802Srene.dejong@arm.com            transactionStart[count] = curTick(); //note the start time
131110802Srene.dejong@arm.com            ++activeDoorbells;
131210802Srene.dejong@arm.com            stats.maxDoorbell = (stats.maxDoorbell.value() < activeDoorbells)
131310802Srene.dejong@arm.com                ? activeDoorbells : stats.maxDoorbell.value();
131410802Srene.dejong@arm.com            stats.averageDoorbell = stats.maxDoorbell.value();
131510802Srene.dejong@arm.com
131610802Srene.dejong@arm.com            /**
131710802Srene.dejong@arm.com             * step3 start transfer
131810802Srene.dejong@arm.com             * step4 register information; allowing the host to respond in
131910802Srene.dejong@arm.com             * the end
132010802Srene.dejong@arm.com             */
132110802Srene.dejong@arm.com            transferstart_info.mask = mask << count;
132210802Srene.dejong@arm.com            transferstart_info.address = address;
132310802Srene.dejong@arm.com            transferstart_info.size = size;
132410802Srene.dejong@arm.com            transferstart_info.done = UFSHCIMem.TRUTRLDBR;
132510802Srene.dejong@arm.com            transferStartInfo.push_back(transferstart_info);
132610802Srene.dejong@arm.com
132710802Srene.dejong@arm.com            /**Deleted in readDone, queued in finalUTP*/
132810802Srene.dejong@arm.com            transferStartInfo.back().destination = new struct
132910802Srene.dejong@arm.com                UTPTransferReqDesc;
133010802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Initial transfer start: 0x%8x\n",
133110802Srene.dejong@arm.com                    transferstart_info.done);
133212087Sspwilson2@wisc.edu            transferEventQueue.push_back(
133312087Sspwilson2@wisc.edu                EventFunctionWrapper([this]{ transferStart(); }, name()));
133410802Srene.dejong@arm.com
133510802Srene.dejong@arm.com            if (transferEventQueue.size() < 2) {
133610802Srene.dejong@arm.com                writeDevice(&transferEventQueue.front(), false,
133710802Srene.dejong@arm.com                            address, size, reinterpret_cast<uint8_t*>
133810802Srene.dejong@arm.com                            (transferStartInfo.front().destination),0, 0);
133910802Srene.dejong@arm.com                DPRINTF(UFSHostDevice, "Transfer scheduled\n");
134010802Srene.dejong@arm.com            }
134110802Srene.dejong@arm.com        }
134210802Srene.dejong@arm.com    }
134310802Srene.dejong@arm.com}
134410802Srene.dejong@arm.com
134510802Srene.dejong@arm.com/**
134610802Srene.dejong@arm.com * Task start event
134710802Srene.dejong@arm.com */
134810802Srene.dejong@arm.com
134910802Srene.dejong@arm.comvoid
135010802Srene.dejong@arm.comUFSHostDevice::taskStart()
135110802Srene.dejong@arm.com{
135210802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Task start");
135310802Srene.dejong@arm.com    taskHandler(&taskInfo.front().destination, taskInfo.front().mask,
135410802Srene.dejong@arm.com                taskInfo.front().address, taskInfo.front().size);
135510802Srene.dejong@arm.com    taskInfo.pop_front();
135610802Srene.dejong@arm.com    taskEventQueue.pop_front();
135710802Srene.dejong@arm.com}
135810802Srene.dejong@arm.com
135910802Srene.dejong@arm.com/**
136010802Srene.dejong@arm.com * Transfer start event
136110802Srene.dejong@arm.com */
136210802Srene.dejong@arm.com
136310802Srene.dejong@arm.comvoid
136410802Srene.dejong@arm.comUFSHostDevice::transferStart()
136510802Srene.dejong@arm.com{
136610802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Enter transfer event\n");
136710802Srene.dejong@arm.com    transferHandler(transferStartInfo.front().destination,
136810802Srene.dejong@arm.com                    transferStartInfo.front().mask,
136910802Srene.dejong@arm.com                    transferStartInfo.front().address,
137010802Srene.dejong@arm.com                    transferStartInfo.front().size,
137110802Srene.dejong@arm.com                    transferStartInfo.front().done);
137210802Srene.dejong@arm.com
137310802Srene.dejong@arm.com    transferStartInfo.pop_front();
137410802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Transfer queue size at end of event: "
137510802Srene.dejong@arm.com            "0x%8x\n", transferEventQueue.size());
137610802Srene.dejong@arm.com}
137710802Srene.dejong@arm.com
137810802Srene.dejong@arm.com/**
137910802Srene.dejong@arm.com * Handles the commands that are given. At this point in time, not many
138010802Srene.dejong@arm.com * commands have been implemented in the driver.
138110802Srene.dejong@arm.com */
138210802Srene.dejong@arm.com
138310802Srene.dejong@arm.comvoid
138410802Srene.dejong@arm.comUFSHostDevice::commandHandler()
138510802Srene.dejong@arm.com{
138610802Srene.dejong@arm.com    if (UFSHCIMem.CMDUICCMDR == 0x16) {
138710802Srene.dejong@arm.com        UFSHCIMem.ORHostControllerStatus |= 0x0F;//link startup
138810802Srene.dejong@arm.com    }
138910802Srene.dejong@arm.com
139010802Srene.dejong@arm.com}
139110802Srene.dejong@arm.com
139210802Srene.dejong@arm.com/**
139310802Srene.dejong@arm.com * Handles the tasks that are given. At this point in time, not many tasks
139410802Srene.dejong@arm.com * have been implemented in the driver.
139510802Srene.dejong@arm.com */
139610802Srene.dejong@arm.com
139710802Srene.dejong@arm.comvoid
139810802Srene.dejong@arm.comUFSHostDevice::taskHandler(struct UTPUPIUTaskReq* request_in,
139910802Srene.dejong@arm.com                           uint32_t req_pos, Addr finaladdress, uint32_t
140010802Srene.dejong@arm.com                           finalsize)
140110802Srene.dejong@arm.com{
140210802Srene.dejong@arm.com    /**
140310802Srene.dejong@arm.com     * For now, just unpack and acknowledge the task without doing anything.
140410802Srene.dejong@arm.com     * TODO Implement UFS tasks.
140510802Srene.dejong@arm.com     */
140610802Srene.dejong@arm.com    inform("taskHandler\n");
140710802Srene.dejong@arm.com    inform("%8x\n", request_in->header.dWord0);
140810802Srene.dejong@arm.com    inform("%8x\n", request_in->header.dWord1);
140910802Srene.dejong@arm.com    inform("%8x\n", request_in->header.dWord2);
141010802Srene.dejong@arm.com
141110802Srene.dejong@arm.com    request_in->header.dWord2 &= 0xffffff00;
141210802Srene.dejong@arm.com
141310802Srene.dejong@arm.com    UFSHCIMem.TMUTMRLDBR &= ~(req_pos);
141410802Srene.dejong@arm.com    taskCommandTrack &= ~(req_pos);
141510802Srene.dejong@arm.com    UFSHCIMem.ORInterruptStatus |= UTPTaskREQCOMPL;
141610802Srene.dejong@arm.com
141710802Srene.dejong@arm.com    readDevice(true, finaladdress, finalsize, reinterpret_cast<uint8_t*>
141810802Srene.dejong@arm.com               (request_in), true, NULL);
141910802Srene.dejong@arm.com
142010802Srene.dejong@arm.com}
142110802Srene.dejong@arm.com
142210802Srene.dejong@arm.com/**
142310802Srene.dejong@arm.com * Obtains the SCSI command (if any)
142410802Srene.dejong@arm.com * Two possibilities: if it contains a SCSI command, then it is a usable
142510802Srene.dejong@arm.com * message; if it doesnt contain a SCSI message, then it can't be handeld
142610802Srene.dejong@arm.com * by this code.
142710802Srene.dejong@arm.com * This is the second stage of the transfer. We have the information about
142810802Srene.dejong@arm.com * where the next command can be found and what the type of command is. The
142910802Srene.dejong@arm.com * actions that are needed from the device its side are: get the information
143010802Srene.dejong@arm.com * and store the information such that we can reply.
143110802Srene.dejong@arm.com */
143210802Srene.dejong@arm.com
143310802Srene.dejong@arm.comvoid
143410802Srene.dejong@arm.comUFSHostDevice::transferHandler(struct UTPTransferReqDesc* request_in,
143510802Srene.dejong@arm.com                               int req_pos, Addr finaladdress, uint32_t
143610802Srene.dejong@arm.com                               finalsize, uint32_t done)
143710802Srene.dejong@arm.com{
143810802Srene.dejong@arm.com
143910802Srene.dejong@arm.com    Addr cmd_desc_addr = 0x00;
144010802Srene.dejong@arm.com
144110802Srene.dejong@arm.com
144210802Srene.dejong@arm.com    //acknowledge handling of the message
144310802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI message detected\n");
144410802Srene.dejong@arm.com    request_in->header.dWord2 &= 0xffffff00;
144510802Srene.dejong@arm.com    SCSIInfo.RequestIn = request_in;
144610802Srene.dejong@arm.com    SCSIInfo.reqPos = req_pos;
144710802Srene.dejong@arm.com    SCSIInfo.finalAddress = finaladdress;
144810802Srene.dejong@arm.com    SCSIInfo.finalSize = finalsize;
144910802Srene.dejong@arm.com    SCSIInfo.destination.resize(request_in->PRDTableOffset * 4
145010802Srene.dejong@arm.com        + request_in->PRDTableLength * sizeof(UFSHCDSGEntry));
145110802Srene.dejong@arm.com    SCSIInfo.done = done;
145210802Srene.dejong@arm.com
145310802Srene.dejong@arm.com    assert(!SCSIResumeEvent.scheduled());
145410802Srene.dejong@arm.com    /**
145510802Srene.dejong@arm.com     *Get the UTP command that has the SCSI command
145610802Srene.dejong@arm.com     */
145710802Srene.dejong@arm.com    cmd_desc_addr = request_in->commandDescBaseAddrHi;
145810802Srene.dejong@arm.com    cmd_desc_addr = (cmd_desc_addr << 32) |
145910802Srene.dejong@arm.com        (request_in->commandDescBaseAddrLo & 0xffffffff);
146010802Srene.dejong@arm.com
146110802Srene.dejong@arm.com    writeDevice(&SCSIResumeEvent, false, cmd_desc_addr,
146210802Srene.dejong@arm.com                SCSIInfo.destination.size(), &SCSIInfo.destination[0],0, 0);
146310802Srene.dejong@arm.com
146410802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI scheduled\n");
146510802Srene.dejong@arm.com
146610802Srene.dejong@arm.com    transferEventQueue.pop_front();
146710802Srene.dejong@arm.com}
146810802Srene.dejong@arm.com
146910802Srene.dejong@arm.com/**
147010802Srene.dejong@arm.com * Obtain LUN and put it in the right LUN queue. Each LUN has its own queue
147110802Srene.dejong@arm.com * of commands that need to be executed. This is the first instance where it
147210802Srene.dejong@arm.com * can be determined which Logic unit should handle the transfer. Then check
147310802Srene.dejong@arm.com * wether it should wait and queue or if it can continue.
147410802Srene.dejong@arm.com */
147510802Srene.dejong@arm.com
147610802Srene.dejong@arm.comvoid
147710802Srene.dejong@arm.comUFSHostDevice::SCSIStart()
147810802Srene.dejong@arm.com{
147910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI message on hold until ready\n");
148010802Srene.dejong@arm.com    uint32_t LUN = SCSIInfo.destination[2];
148110802Srene.dejong@arm.com    UFSDevice[LUN]->SCSIInfoQueue.push_back(SCSIInfo);
148210802Srene.dejong@arm.com
148310802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI queue %d has %d elements\n", LUN,
148410802Srene.dejong@arm.com            UFSDevice[LUN]->SCSIInfoQueue.size());
148510802Srene.dejong@arm.com
148610802Srene.dejong@arm.com    /**There are 32 doorbells, so at max there can be 32 transactions*/
148710802Srene.dejong@arm.com    if (UFSDevice[LUN]->SCSIInfoQueue.size() < 2) //LUN is available
148810802Srene.dejong@arm.com        SCSIResume(LUN);
148910802Srene.dejong@arm.com
149010802Srene.dejong@arm.com    else if (UFSDevice[LUN]->SCSIInfoQueue.size() > 32)
149110802Srene.dejong@arm.com        panic("SCSI queue is getting too big %d\n", UFSDevice[LUN]->
149210802Srene.dejong@arm.com              SCSIInfoQueue.size());
149310802Srene.dejong@arm.com
149410802Srene.dejong@arm.com    /**
149510802Srene.dejong@arm.com     * First transfer is done, fetch the next;
149610802Srene.dejong@arm.com     * At this point, the device is busy, not the HC
149710802Srene.dejong@arm.com     */
149810802Srene.dejong@arm.com    if (!transferEventQueue.empty()) {
149910802Srene.dejong@arm.com
150010802Srene.dejong@arm.com        /**
150110802Srene.dejong@arm.com         * loading next data packet in case Another LUN
150210802Srene.dejong@arm.com         * is approached in the mean time
150310802Srene.dejong@arm.com         */
150410802Srene.dejong@arm.com        writeDevice(&transferEventQueue.front(), false,
150510802Srene.dejong@arm.com                    transferStartInfo.front().address,
150610802Srene.dejong@arm.com                    transferStartInfo.front().size, reinterpret_cast<uint8_t*>
150710802Srene.dejong@arm.com                    (transferStartInfo.front().destination), 0, 0);
150810802Srene.dejong@arm.com
150910802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Transfer scheduled");
151010802Srene.dejong@arm.com    }
151110802Srene.dejong@arm.com}
151210802Srene.dejong@arm.com
151310802Srene.dejong@arm.com/**
151410802Srene.dejong@arm.com * Handles the transfer requests that are given.
151510802Srene.dejong@arm.com * There can be three types of transfer. SCSI specific, Reads and writes
151610802Srene.dejong@arm.com * apart from the data transfer, this also generates its own reply (UPIU
151710802Srene.dejong@arm.com * response). Information for this reply is stored in transferInfo and will
151810802Srene.dejong@arm.com * be used in transferDone
151910802Srene.dejong@arm.com */
152010802Srene.dejong@arm.com
152110802Srene.dejong@arm.comvoid
152210802Srene.dejong@arm.comUFSHostDevice::SCSIResume(uint32_t lun_id)
152310802Srene.dejong@arm.com{
152410802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSIresume\n");
152510802Srene.dejong@arm.com    if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
152610802Srene.dejong@arm.com        panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
152710802Srene.dejong@arm.com              UFSHCIMem.TRUTRLDBR);
152810802Srene.dejong@arm.com
152910802Srene.dejong@arm.com    /**old info, lets form it such that we can understand it*/
153010802Srene.dejong@arm.com    struct UTPTransferReqDesc* request_in = UFSDevice[lun_id]->
153110802Srene.dejong@arm.com        SCSIInfoQueue.front().RequestIn;
153210802Srene.dejong@arm.com
153310802Srene.dejong@arm.com    uint32_t req_pos = UFSDevice[lun_id]->SCSIInfoQueue.front().reqPos;
153410802Srene.dejong@arm.com
153510802Srene.dejong@arm.com    Addr finaladdress = UFSDevice[lun_id]->SCSIInfoQueue.front().
153610802Srene.dejong@arm.com        finalAddress;
153710802Srene.dejong@arm.com
153810802Srene.dejong@arm.com    uint32_t finalsize = UFSDevice[lun_id]->SCSIInfoQueue.front().finalSize;
153910802Srene.dejong@arm.com
154010802Srene.dejong@arm.com    uint32_t* transfercommand = reinterpret_cast<uint32_t*>
154110802Srene.dejong@arm.com        (&(UFSDevice[lun_id]->SCSIInfoQueue.front().destination[0]));
154210802Srene.dejong@arm.com
154310802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Task tag: 0x%8x\n", transfercommand[0]>>24);
154410802Srene.dejong@arm.com    /**call logic unit to handle SCSI command*/
154510802Srene.dejong@arm.com    request_out_datain = UFSDevice[(transfercommand[0] & 0xFF0000) >> 16]->
154610802Srene.dejong@arm.com        SCSICMDHandle(transfercommand);
154710802Srene.dejong@arm.com
154810802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "LUN: %d\n", request_out_datain.LUN);
154910802Srene.dejong@arm.com
155010802Srene.dejong@arm.com    /**
155110802Srene.dejong@arm.com     * build response stating that it was succesful
155210802Srene.dejong@arm.com     * command completion, Logic unit number, and Task tag
155310802Srene.dejong@arm.com     */
155410802Srene.dejong@arm.com    request_in->header.dWord0 = ((request_in->header.dWord0 >> 24) == 0x21)
155510802Srene.dejong@arm.com        ? 0x36 : 0x21;
155610802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord0 =
155710802Srene.dejong@arm.com        request_in->header.dWord0 | (request_out_datain.LUN << 8)
155810802Srene.dejong@arm.com        | (transfercommand[0] & 0xFF000000);
155910802Srene.dejong@arm.com    /**SCSI status reply*/
156010802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord1 = 0x00000000 |
156110802Srene.dejong@arm.com        (request_out_datain.status << 24);
156210802Srene.dejong@arm.com    /**segment size + EHS length (see UFS standard ch7)*/
156310802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord2 = 0x00000000 |
156410802Srene.dejong@arm.com        ((request_out_datain.senseSize + 2) << 24) | 0x05;
156510802Srene.dejong@arm.com    /**amount of data that will follow*/
156610802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.requestOut.senseDataLen =
156710802Srene.dejong@arm.com        request_out_datain.senseSize;
156810802Srene.dejong@arm.com
156910802Srene.dejong@arm.com    //data
157010802Srene.dejong@arm.com    for (uint8_t count = 0; count<request_out_datain.senseSize; count++) {
157110802Srene.dejong@arm.com        UFSDevice[lun_id]->transferInfo.requestOut.senseData[count] =
157210802Srene.dejong@arm.com            request_out_datain.senseCode[count + 1];
157310802Srene.dejong@arm.com    }
157410802Srene.dejong@arm.com
157510802Srene.dejong@arm.com    /*
157610802Srene.dejong@arm.com     * At position defined by "request_in->PRDTableOffset" (counting 32 bit
157710802Srene.dejong@arm.com     * words) in array "transfercommand" we have a scatter gather list, which
157810802Srene.dejong@arm.com     * is usefull to us if we interpreted it as a UFSHCDSGEntry structure.
157910802Srene.dejong@arm.com     */
158010802Srene.dejong@arm.com    struct UFSHCDSGEntry* sglist =  reinterpret_cast<UFSHCDSGEntry*>
158110802Srene.dejong@arm.com        (&(transfercommand[(request_in->PRDTableOffset)]));
158210802Srene.dejong@arm.com
158310802Srene.dejong@arm.com    uint32_t length = request_in->PRDTableLength;
158410802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "# PRDT entries: %d\n", length);
158510802Srene.dejong@arm.com
158610802Srene.dejong@arm.com    Addr response_addr = request_in->commandDescBaseAddrHi;
158710802Srene.dejong@arm.com    response_addr = (response_addr << 32) |
158810802Srene.dejong@arm.com        ((request_in->commandDescBaseAddrLo +
158910802Srene.dejong@arm.com          (request_in->responseUPIULength << 2)) & 0xffffffff);
159010802Srene.dejong@arm.com
159110802Srene.dejong@arm.com    /**transferdone information packet filling*/
159210802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.responseStartAddr = response_addr;
159310802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.reqPos = req_pos;
159410802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.size = finalsize;
159510802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.address = finaladdress;
159610802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.destination = reinterpret_cast<uint8_t*>
159710802Srene.dejong@arm.com        (UFSDevice[lun_id]->SCSIInfoQueue.front().RequestIn);
159810802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.finished = true;
159910802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.lunID = request_out_datain.LUN;
160010802Srene.dejong@arm.com
160110802Srene.dejong@arm.com    /**
160210802Srene.dejong@arm.com     * In this part the data that needs to be transfered will be initiated
160310802Srene.dejong@arm.com     * and the chain of DMA (and potentially) disk transactions will be
160410802Srene.dejong@arm.com     * started.
160510802Srene.dejong@arm.com     */
160610802Srene.dejong@arm.com    if (request_out_datain.expectMore == 0x01) {
160710802Srene.dejong@arm.com        /**write transfer*/
160810802Srene.dejong@arm.com        manageWriteTransfer(request_out_datain.LUN, request_out_datain.offset,
160910802Srene.dejong@arm.com                            length, sglist);
161010802Srene.dejong@arm.com
161110802Srene.dejong@arm.com    } else if (request_out_datain.expectMore == 0x02) {
161210802Srene.dejong@arm.com        /**read transfer*/
161310802Srene.dejong@arm.com        manageReadTransfer(request_out_datain.msgSize, request_out_datain.LUN,
161410802Srene.dejong@arm.com                           request_out_datain.offset, length, sglist);
161510802Srene.dejong@arm.com
161610802Srene.dejong@arm.com    } else {
161710802Srene.dejong@arm.com        /**not disk related transfer, SCSI maintanance*/
161810802Srene.dejong@arm.com        uint32_t count = 0;
161910802Srene.dejong@arm.com        uint32_t size_accum = 0;
162010802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
162110802Srene.dejong@arm.com                request_out_datain.msgSize);
162210802Srene.dejong@arm.com
162310802Srene.dejong@arm.com        /**Transport the SCSI reponse data according to the SG list*/
162410802Srene.dejong@arm.com        while ((length > count) && size_accum
162510802Srene.dejong@arm.com               < (request_out_datain.msgSize - 1) &&
162610802Srene.dejong@arm.com               (request_out_datain.msgSize != 0x00)) {
162710802Srene.dejong@arm.com            Addr SCSI_start = sglist[count].upperAddr;
162810802Srene.dejong@arm.com            SCSI_start = (SCSI_start << 32) |
162910802Srene.dejong@arm.com                (sglist[count].baseAddr & 0xFFFFFFFF);
163010802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Data DMA start: 0x%8x\n", SCSI_start);
163110802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
163210802Srene.dejong@arm.com                    (sglist[count].size + 1));
163310802Srene.dejong@arm.com            /**
163410802Srene.dejong@arm.com             * safetynet; it has been shown that sg list may be optimistic in
163510802Srene.dejong@arm.com             * the amount of data allocated, which can potentially lead to
163610802Srene.dejong@arm.com             * some garbage data being send over. Hence this construction
163710802Srene.dejong@arm.com             * that finds the least amount of data that needs to be
163810802Srene.dejong@arm.com             * transfered.
163910802Srene.dejong@arm.com             */
164010802Srene.dejong@arm.com            uint32_t size_to_send = sglist[count].size + 1;
164110802Srene.dejong@arm.com
164210802Srene.dejong@arm.com            if (request_out_datain.msgSize < (size_to_send + size_accum))
164310802Srene.dejong@arm.com                size_to_send = request_out_datain.msgSize - size_accum;
164410802Srene.dejong@arm.com
164510802Srene.dejong@arm.com            readDevice(false, SCSI_start, size_to_send,
164610802Srene.dejong@arm.com                       reinterpret_cast<uint8_t*>
164710802Srene.dejong@arm.com                       (&(request_out_datain.message.dataMsg[size_accum])),
164810802Srene.dejong@arm.com                       false, NULL);
164910802Srene.dejong@arm.com
165010802Srene.dejong@arm.com            size_accum += size_to_send;
165110802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Total remaining: 0x%8x,accumulated so far"
165210802Srene.dejong@arm.com                    " : 0x%8x\n", (request_out_datain.msgSize - size_accum),
165310802Srene.dejong@arm.com                    size_accum);
165410802Srene.dejong@arm.com
165510802Srene.dejong@arm.com            ++count;
165610802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Transfer #: %d\n", count);
165710802Srene.dejong@arm.com        }
165810802Srene.dejong@arm.com
165910802Srene.dejong@arm.com        /**Go to the next stage of the answering process*/
166010802Srene.dejong@arm.com        transferDone(response_addr, req_pos, UFSDevice[lun_id]->
166110802Srene.dejong@arm.com                     transferInfo.requestOut, finalsize, finaladdress,
166210802Srene.dejong@arm.com                     reinterpret_cast<uint8_t*>(request_in), true, lun_id);
166310802Srene.dejong@arm.com    }
166410802Srene.dejong@arm.com
166510802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI resume done\n");
166610802Srene.dejong@arm.com}
166710802Srene.dejong@arm.com
166810802Srene.dejong@arm.com/**
166910802Srene.dejong@arm.com * Find finished transfer. Callback function. One of the LUNs is done with
167010802Srene.dejong@arm.com * the disk transfer and reports back to the controller. This function finds
167110802Srene.dejong@arm.com * out who it was, and calls transferDone.
167210802Srene.dejong@arm.com */
167310802Srene.dejong@arm.comvoid
167410802Srene.dejong@arm.comUFSHostDevice::LUNSignal()
167510802Srene.dejong@arm.com{
167610802Srene.dejong@arm.com    uint8_t this_lun = 0;
167710802Srene.dejong@arm.com
167810802Srene.dejong@arm.com    //while we haven't found the right lun, keep searching
167911321Ssteve.reinhardt@amd.com    while ((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedCommand())
168010802Srene.dejong@arm.com        ++this_lun;
168110802Srene.dejong@arm.com
168210802Srene.dejong@arm.com    if (this_lun < lunAvail) {
168310802Srene.dejong@arm.com        //Clear signal.
168410802Srene.dejong@arm.com        UFSDevice[this_lun]->clearSignal();
168510802Srene.dejong@arm.com        //found it; call transferDone
168610802Srene.dejong@arm.com        transferDone(UFSDevice[this_lun]->transferInfo.responseStartAddr,
168710802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.reqPos,
168810802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.requestOut,
168910802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.size,
169010802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.address,
169110802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.destination,
169210802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.finished,
169310802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.lunID);
169410802Srene.dejong@arm.com    }
169510802Srene.dejong@arm.com
169610802Srene.dejong@arm.com    else
169710802Srene.dejong@arm.com        panic("no LUN finished in tick %d\n", curTick());
169810802Srene.dejong@arm.com}
169910802Srene.dejong@arm.com
170010802Srene.dejong@arm.com/**
170110802Srene.dejong@arm.com * Transfer done. When the data transfer is done, this function ensures
170210802Srene.dejong@arm.com * that the application is notified.
170310802Srene.dejong@arm.com */
170410802Srene.dejong@arm.com
170510802Srene.dejong@arm.comvoid
170610802Srene.dejong@arm.comUFSHostDevice::transferDone(Addr responseStartAddr, uint32_t req_pos,
170710802Srene.dejong@arm.com                            struct UTPUPIURSP request_out, uint32_t size,
170810802Srene.dejong@arm.com                            Addr address, uint8_t* destination,
170910802Srene.dejong@arm.com                            bool finished, uint32_t lun_id)
171010802Srene.dejong@arm.com{
171110802Srene.dejong@arm.com    /**Test whether SCSI queue hasn't popped prematurely*/
171210802Srene.dejong@arm.com    if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
171310802Srene.dejong@arm.com        panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
171410802Srene.dejong@arm.com              UFSHCIMem.TRUTRLDBR);
171510802Srene.dejong@arm.com
171610802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "DMA start: 0x%8x; DMA size: 0x%8x\n",
171710802Srene.dejong@arm.com            responseStartAddr, sizeof(request_out));
171810802Srene.dejong@arm.com
171910802Srene.dejong@arm.com    struct transferStart lastinfo;
172010802Srene.dejong@arm.com    lastinfo.mask = req_pos;
172110802Srene.dejong@arm.com    lastinfo.done = finished;
172210802Srene.dejong@arm.com    lastinfo.address = address;
172310802Srene.dejong@arm.com    lastinfo.size = size;
172410802Srene.dejong@arm.com    lastinfo.destination = reinterpret_cast<UTPTransferReqDesc*>
172510802Srene.dejong@arm.com        (destination);
172610802Srene.dejong@arm.com    lastinfo.lun_id = lun_id;
172710802Srene.dejong@arm.com
172810802Srene.dejong@arm.com    transferEnd.push_back(lastinfo);
172910802Srene.dejong@arm.com
173010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Transfer done start\n");
173110802Srene.dejong@arm.com
173210802Srene.dejong@arm.com    readDevice(false, responseStartAddr, sizeof(request_out),
173310802Srene.dejong@arm.com               reinterpret_cast<uint8_t*>
173410802Srene.dejong@arm.com               (&(UFSDevice[lun_id]->transferInfo.requestOut)),
173510802Srene.dejong@arm.com               true, &UTPEvent);
173610802Srene.dejong@arm.com}
173710802Srene.dejong@arm.com
173810802Srene.dejong@arm.com/**
173910802Srene.dejong@arm.com * finalUTP. Second part of the transfer done event.
174010802Srene.dejong@arm.com * this sends the final response: the UTP response. After this transaction
174110802Srene.dejong@arm.com * the doorbell shall be cleared, and the interupt shall be set.
174210802Srene.dejong@arm.com */
174310802Srene.dejong@arm.com
174410802Srene.dejong@arm.comvoid
174510802Srene.dejong@arm.comUFSHostDevice::finalUTP()
174610802Srene.dejong@arm.com{
174710802Srene.dejong@arm.com    uint32_t lun_id = transferEnd.front().lun_id;
174810802Srene.dejong@arm.com
174910802Srene.dejong@arm.com    UFSDevice[lun_id]->SCSIInfoQueue.pop_front();
175010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSIInfoQueue size: %d, lun: %d\n",
175110802Srene.dejong@arm.com            UFSDevice[lun_id]->SCSIInfoQueue.size(), lun_id);
175210802Srene.dejong@arm.com
175310802Srene.dejong@arm.com    /**stats**/
175410802Srene.dejong@arm.com    if (UFSHCIMem.TRUTRLDBR & transferEnd.front().mask) {
175510802Srene.dejong@arm.com        uint8_t count = 0;
175610802Srene.dejong@arm.com        while (!(transferEnd.front().mask & (0x1 << count)))
175710802Srene.dejong@arm.com            ++count;
175810802Srene.dejong@arm.com        stats.transactionLatency.sample(curTick() -
175910802Srene.dejong@arm.com                                        transactionStart[count]);
176010802Srene.dejong@arm.com    }
176110802Srene.dejong@arm.com
176210802Srene.dejong@arm.com    /**Last message that will be transfered*/
176310802Srene.dejong@arm.com    readDevice(true, transferEnd.front().address,
176410802Srene.dejong@arm.com               transferEnd.front().size, reinterpret_cast<uint8_t*>
176510802Srene.dejong@arm.com               (transferEnd.front().destination), true, NULL);
176610802Srene.dejong@arm.com
176710802Srene.dejong@arm.com    /**clean and ensure that the tracker is updated*/
176810802Srene.dejong@arm.com    transferTrack &= ~(transferEnd.front().mask);
176910802Srene.dejong@arm.com    --activeDoorbells;
177010802Srene.dejong@arm.com    ++pendingDoorbells;
177110802Srene.dejong@arm.com    garbage.push_back(transferEnd.front().destination);
177210802Srene.dejong@arm.com    transferEnd.pop_front();
177310802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "UTP handled\n");
177410802Srene.dejong@arm.com
177510802Srene.dejong@arm.com    /**stats**/
177610802Srene.dejong@arm.com    stats.averageDoorbell = stats.maxDoorbell.value();
177710802Srene.dejong@arm.com
177810802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "activeDoorbells: %d, pendingDoorbells: %d,"
177910802Srene.dejong@arm.com            " garbage: %d, TransferEvent: %d\n", activeDoorbells,
178010802Srene.dejong@arm.com            pendingDoorbells, garbage.size(), transferEventQueue.size());
178110802Srene.dejong@arm.com
178210802Srene.dejong@arm.com    /**This is the moment that the device is available again*/
178310802Srene.dejong@arm.com    if (!UFSDevice[lun_id]->SCSIInfoQueue.empty())
178410802Srene.dejong@arm.com        SCSIResume(lun_id);
178510802Srene.dejong@arm.com}
178610802Srene.dejong@arm.com
178710802Srene.dejong@arm.com/**
178810802Srene.dejong@arm.com * Read done handling function, is only initiated at the end of a transaction
178910802Srene.dejong@arm.com */
179010802Srene.dejong@arm.comvoid
179110802Srene.dejong@arm.comUFSHostDevice::readDone()
179210802Srene.dejong@arm.com{
179310802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Read done start\n");
179410802Srene.dejong@arm.com    --readPendingNum;
179510802Srene.dejong@arm.com
179610802Srene.dejong@arm.com    /**Garbage collection; sort out the allocated UTP descriptor*/
179710802Srene.dejong@arm.com    if (garbage.size() > 0) {
179810802Srene.dejong@arm.com        delete garbage.front();
179910802Srene.dejong@arm.com        garbage.pop_front();
180010802Srene.dejong@arm.com        }
180110802Srene.dejong@arm.com
180210802Srene.dejong@arm.com    /**done, generate interrupt if we havent got one already*/
180311321Ssteve.reinhardt@amd.com    if (!(UFSHCIMem.ORInterruptStatus & 0x01)) {
180410802Srene.dejong@arm.com        UFSHCIMem.ORInterruptStatus |= UTPTransferREQCOMPL;
180510802Srene.dejong@arm.com        generateInterrupt();
180610802Srene.dejong@arm.com    }
180710802Srene.dejong@arm.com
180810802Srene.dejong@arm.com
180911321Ssteve.reinhardt@amd.com    if (!readDoneEvent.empty()) {
181010802Srene.dejong@arm.com        readDoneEvent.pop_front();
181110802Srene.dejong@arm.com    }
181210802Srene.dejong@arm.com}
181310802Srene.dejong@arm.com
181410802Srene.dejong@arm.com/**
181510802Srene.dejong@arm.com * set interrupt and sort out the doorbell register.
181610802Srene.dejong@arm.com */
181710802Srene.dejong@arm.com
181810802Srene.dejong@arm.comvoid
181910802Srene.dejong@arm.comUFSHostDevice::generateInterrupt()
182010802Srene.dejong@arm.com{
182110802Srene.dejong@arm.com    /**just to keep track of the transactions*/
182210802Srene.dejong@arm.com    countInt++;
182310802Srene.dejong@arm.com
182410802Srene.dejong@arm.com    /**step5 clear doorbell*/
182510802Srene.dejong@arm.com    UFSHCIMem.TRUTRLDBR &= transferTrack;
182610802Srene.dejong@arm.com    pendingDoorbells = 0;
182710802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Clear doorbell %X\n", UFSHCIMem.TRUTRLDBR);
182810802Srene.dejong@arm.com
182911179Ssascha.bischoff@ARM.com    checkDrain();
183011179Ssascha.bischoff@ARM.com
183110802Srene.dejong@arm.com    /**step6 raise interrupt*/
183210802Srene.dejong@arm.com    gic->sendInt(intNum);
183310802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Send interrupt @ transaction: 0x%8x!\n",
183410802Srene.dejong@arm.com            countInt);
183510802Srene.dejong@arm.com}
183610802Srene.dejong@arm.com
183710802Srene.dejong@arm.com/**
183810802Srene.dejong@arm.com * Clear interrupt
183910802Srene.dejong@arm.com */
184010802Srene.dejong@arm.com
184110802Srene.dejong@arm.comvoid
184210802Srene.dejong@arm.comUFSHostDevice::clearInterrupt()
184310802Srene.dejong@arm.com{
184410802Srene.dejong@arm.com    gic->clearInt(intNum);
184510802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Clear interrupt: 0x%8x!\n", countInt);
184610802Srene.dejong@arm.com
184711179Ssascha.bischoff@ARM.com    checkDrain();
184811179Ssascha.bischoff@ARM.com
184910802Srene.dejong@arm.com    if (!(UFSHCIMem.TRUTRLDBR)) {
185010802Srene.dejong@arm.com        idlePhaseStart = curTick();
185110802Srene.dejong@arm.com    }
185210802Srene.dejong@arm.com    /**end of a transaction*/
185310802Srene.dejong@arm.com}
185410802Srene.dejong@arm.com
185510802Srene.dejong@arm.com/**
185610802Srene.dejong@arm.com * Important to understand about the transfer flow:
185710802Srene.dejong@arm.com * We have basically three stages, The "system memory" stage, the "device
185810802Srene.dejong@arm.com * buffer" stage and the "disk" stage. In this model we assume an infinite
185910802Srene.dejong@arm.com * buffer, or a buffer that is big enough to store all the data in the
186010802Srene.dejong@arm.com * biggest transaction. Between the three stages are two queues. Those queues
186110802Srene.dejong@arm.com * store the messages to simulate their transaction from one stage to the
186210802Srene.dejong@arm.com * next. The manage{Action} function fills up one of the queues and triggers
186310802Srene.dejong@arm.com * the first event, which causes a chain reaction of events executed once
186410802Srene.dejong@arm.com * they pass through their queues. For a write action the stages are ordered
186510802Srene.dejong@arm.com * "system memory", "device buffer" and "disk", whereas the read transfers
186610802Srene.dejong@arm.com * happen "disk", "device buffer" and "system memory". The dma action in the
186710802Srene.dejong@arm.com * dma device is written from a bus perspective whereas this model is written
186810802Srene.dejong@arm.com * from a device perspective. To avoid confusion, the translation between the
186910802Srene.dejong@arm.com * two has been made in the writeDevice and readDevice funtions.
187010802Srene.dejong@arm.com */
187110802Srene.dejong@arm.com
187210802Srene.dejong@arm.com
187310802Srene.dejong@arm.com/**
187410802Srene.dejong@arm.com * Dma transaction function: write device. Note that the dma action is
187510802Srene.dejong@arm.com * from a device perspective, while this function is from an initiator
187610802Srene.dejong@arm.com * perspective
187710802Srene.dejong@arm.com */
187810802Srene.dejong@arm.com
187910802Srene.dejong@arm.comvoid
188010802Srene.dejong@arm.comUFSHostDevice::writeDevice(Event* additional_action, bool toDisk, Addr
188110802Srene.dejong@arm.com                           start, int size, uint8_t* destination, uint64_t
188210802Srene.dejong@arm.com                           SCSIDiskOffset, uint32_t lun_id)
188310802Srene.dejong@arm.com{
188410802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write transaction Start: 0x%8x; Size: %d\n",
188510802Srene.dejong@arm.com            start, size);
188610802Srene.dejong@arm.com
188710802Srene.dejong@arm.com    /**check whether transfer is all the way to the flash*/
188810802Srene.dejong@arm.com    if (toDisk) {
188910802Srene.dejong@arm.com        ++writePendingNum;
189010802Srene.dejong@arm.com
189111321Ssteve.reinhardt@amd.com        while (!writeDoneEvent.empty() && (writeDoneEvent.front().when()
189210802Srene.dejong@arm.com                                          < curTick()))
189310802Srene.dejong@arm.com            writeDoneEvent.pop_front();
189410802Srene.dejong@arm.com
189512086Sspwilson2@wisc.edu        writeDoneEvent.push_back(
189612086Sspwilson2@wisc.edu            EventFunctionWrapper([this]{ writeDone(); },
189712086Sspwilson2@wisc.edu                                 name()));
189810802Srene.dejong@arm.com        assert(!writeDoneEvent.back().scheduled());
189910802Srene.dejong@arm.com
190010802Srene.dejong@arm.com        /**destination is an offset here since we are writing to a disk*/
190110802Srene.dejong@arm.com        struct transferInfo new_transfer;
190210802Srene.dejong@arm.com        new_transfer.offset = SCSIDiskOffset;
190310802Srene.dejong@arm.com        new_transfer.size = size;
190410802Srene.dejong@arm.com        new_transfer.lunID = lun_id;
190510802Srene.dejong@arm.com        new_transfer.filePointer = 0;
190610802Srene.dejong@arm.com        SSDWriteinfo.push_back(new_transfer);
190710802Srene.dejong@arm.com
190810802Srene.dejong@arm.com        /**allocate appropriate buffer*/
190910802Srene.dejong@arm.com        SSDWriteinfo.back().buffer.resize(size);
191010802Srene.dejong@arm.com
191110802Srene.dejong@arm.com        /**transaction*/
191210802Srene.dejong@arm.com        dmaPort.dmaAction(MemCmd::ReadReq, start, size,
191310802Srene.dejong@arm.com                          &writeDoneEvent.back(),
191410802Srene.dejong@arm.com                          &SSDWriteinfo.back().buffer[0], 0);
191510802Srene.dejong@arm.com        //yes, a readreq at a write device function is correct.
191610802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write to disk scheduled\n");
191710802Srene.dejong@arm.com
191810802Srene.dejong@arm.com    } else {
191910802Srene.dejong@arm.com        assert(!additional_action->scheduled());
192010802Srene.dejong@arm.com        dmaPort.dmaAction(MemCmd::ReadReq, start, size,
192110802Srene.dejong@arm.com                          additional_action, destination, 0);
192210802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write scheduled\n");
192310802Srene.dejong@arm.com    }
192410802Srene.dejong@arm.com}
192510802Srene.dejong@arm.com
192610802Srene.dejong@arm.com/**
192710802Srene.dejong@arm.com * Manage write transfer. Manages correct transfer flow and makes sure that
192810802Srene.dejong@arm.com * the queues are filled on time
192910802Srene.dejong@arm.com */
193010802Srene.dejong@arm.com
193110802Srene.dejong@arm.comvoid
193210802Srene.dejong@arm.comUFSHostDevice::manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t
193310802Srene.dejong@arm.com                                   sg_table_length, struct UFSHCDSGEntry*
193410802Srene.dejong@arm.com                                   sglist)
193510802Srene.dejong@arm.com{
193610802Srene.dejong@arm.com    struct writeToDiskBurst next_packet;
193710802Srene.dejong@arm.com
193810802Srene.dejong@arm.com    next_packet.SCSIDiskOffset = offset;
193910802Srene.dejong@arm.com
194010802Srene.dejong@arm.com    UFSDevice[LUN]->setTotalWrite(sg_table_length);
194110802Srene.dejong@arm.com
194210802Srene.dejong@arm.com    /**
194310802Srene.dejong@arm.com     * Break-up the transactions into actions defined by the scatter gather
194410802Srene.dejong@arm.com     * list.
194510802Srene.dejong@arm.com     */
194610802Srene.dejong@arm.com    for (uint32_t count = 0; count < sg_table_length; count++) {
194710802Srene.dejong@arm.com        next_packet.start = sglist[count].upperAddr;
194810802Srene.dejong@arm.com        next_packet.start = (next_packet.start << 32) |
194910802Srene.dejong@arm.com            (sglist[count].baseAddr & 0xFFFFFFFF);
195010802Srene.dejong@arm.com        next_packet.LUN = LUN;
195110802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write data DMA start: 0x%8x\n",
195210802Srene.dejong@arm.com                next_packet.start);
195310802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write data DMA size: 0x%8x\n",
195410802Srene.dejong@arm.com                (sglist[count].size + 1));
195510802Srene.dejong@arm.com        assert(sglist[count].size > 0);
195610802Srene.dejong@arm.com
195710802Srene.dejong@arm.com        if (count != 0)
195810802Srene.dejong@arm.com            next_packet.SCSIDiskOffset = next_packet.SCSIDiskOffset +
195910802Srene.dejong@arm.com                (sglist[count - 1].size + 1);
196010802Srene.dejong@arm.com
196110802Srene.dejong@arm.com        next_packet.size = sglist[count].size + 1;
196210802Srene.dejong@arm.com
196310802Srene.dejong@arm.com        /**If the queue is empty, the transaction should be initiated*/
196410802Srene.dejong@arm.com        if (dmaWriteInfo.empty())
196510802Srene.dejong@arm.com            writeDevice(NULL, true, next_packet.start, next_packet.size,
196610802Srene.dejong@arm.com                        NULL, next_packet.SCSIDiskOffset, next_packet.LUN);
196710802Srene.dejong@arm.com        else
196810802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Write not initiated queue: %d\n",
196910802Srene.dejong@arm.com                    dmaWriteInfo.size());
197010802Srene.dejong@arm.com
197110802Srene.dejong@arm.com        dmaWriteInfo.push_back(next_packet);
197210802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write Location: 0x%8x\n",
197310802Srene.dejong@arm.com                next_packet.SCSIDiskOffset);
197410802Srene.dejong@arm.com
197510802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write transfer #: 0x%8x\n", count + 1);
197610802Srene.dejong@arm.com
197710802Srene.dejong@arm.com        /** stats **/
197810802Srene.dejong@arm.com        stats.totalWrittenSSD += (sglist[count].size + 1);
197910802Srene.dejong@arm.com    }
198010802Srene.dejong@arm.com
198110802Srene.dejong@arm.com    /**stats**/
198210802Srene.dejong@arm.com    ++stats.totalWriteUFSTransactions;
198310802Srene.dejong@arm.com}
198410802Srene.dejong@arm.com
198510802Srene.dejong@arm.com/**
198610802Srene.dejong@arm.com * Write done handling function. Is only initiated when the flash is directly
198710802Srene.dejong@arm.com * approached
198810802Srene.dejong@arm.com */
198910802Srene.dejong@arm.com
199010802Srene.dejong@arm.comvoid
199110802Srene.dejong@arm.comUFSHostDevice::writeDone()
199210802Srene.dejong@arm.com{
199310802Srene.dejong@arm.com    /**DMA is done, information no longer needed*/
199410802Srene.dejong@arm.com    assert(dmaWriteInfo.size() > 0);
199510802Srene.dejong@arm.com    dmaWriteInfo.pop_front();
199610802Srene.dejong@arm.com    assert(SSDWriteinfo.size() > 0);
199710802Srene.dejong@arm.com    uint32_t lun = SSDWriteinfo.front().lunID;
199810802Srene.dejong@arm.com
199910802Srene.dejong@arm.com    /**If there is nothing on the way, we need to start the events*/
200010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write done entered, queue: %d\n",
200110802Srene.dejong@arm.com            UFSDevice[lun]->SSDWriteDoneInfo.size());
200210802Srene.dejong@arm.com    /**Write the disk*/
200310802Srene.dejong@arm.com    UFSDevice[lun]->writeFlash(&SSDWriteinfo.front().buffer[0],
200410802Srene.dejong@arm.com                               SSDWriteinfo.front().offset,
200510802Srene.dejong@arm.com                               SSDWriteinfo.front().size);
200610802Srene.dejong@arm.com
200710802Srene.dejong@arm.com    /**
200810802Srene.dejong@arm.com     * Move to the second queue, enter the logic unit
200910802Srene.dejong@arm.com     * This is where the disk is approached and the flash transaction is
201010802Srene.dejong@arm.com     * handled SSDWriteDone will take care of the timing
201110802Srene.dejong@arm.com     */
201210802Srene.dejong@arm.com    UFSDevice[lun]->SSDWriteDoneInfo.push_back(SSDWriteinfo.front());
201310802Srene.dejong@arm.com    SSDWriteinfo.pop_front();
201410802Srene.dejong@arm.com
201510802Srene.dejong@arm.com    --writePendingNum;
201610802Srene.dejong@arm.com    /**so far, only the DMA part has been handled, lets do the disk delay*/
201710802Srene.dejong@arm.com    UFSDevice[lun]->SSDWriteStart();
201810802Srene.dejong@arm.com
201910802Srene.dejong@arm.com    /** stats **/
202010802Srene.dejong@arm.com    stats.currentWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
202110802Srene.dejong@arm.com    stats.averageWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
202210802Srene.dejong@arm.com    ++stats.totalWriteDiskTransactions;
202310802Srene.dejong@arm.com
202410802Srene.dejong@arm.com    /**initiate the next dma action (if any)*/
202510802Srene.dejong@arm.com    if (!dmaWriteInfo.empty())
202610802Srene.dejong@arm.com        writeDevice(NULL, true, dmaWriteInfo.front().start,
202710802Srene.dejong@arm.com                    dmaWriteInfo.front().size,  NULL,
202810802Srene.dejong@arm.com                    dmaWriteInfo.front().SCSIDiskOffset,
202910802Srene.dejong@arm.com                    dmaWriteInfo.front().LUN);
203010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write done end\n");
203110802Srene.dejong@arm.com}
203210802Srene.dejong@arm.com
203310802Srene.dejong@arm.com/**
203410802Srene.dejong@arm.com * SSD write start. Starts the write action in the timing model
203510802Srene.dejong@arm.com */
203610802Srene.dejong@arm.comvoid
203710802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDWriteStart()
203810802Srene.dejong@arm.com{
203910802Srene.dejong@arm.com    assert(SSDWriteDoneInfo.size() > 0);
204010802Srene.dejong@arm.com    flashDevice->writeMemory(
204110802Srene.dejong@arm.com        SSDWriteDoneInfo.front().offset,
204210802Srene.dejong@arm.com        SSDWriteDoneInfo.front().size, memWriteCallback);
204310802Srene.dejong@arm.com
204410802Srene.dejong@arm.com    SSDWriteDoneInfo.pop_front();
204510802Srene.dejong@arm.com
204610802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write is started; left in queue: %d\n",
204710802Srene.dejong@arm.com            SSDWriteDoneInfo.size());
204810802Srene.dejong@arm.com}
204910802Srene.dejong@arm.com
205010802Srene.dejong@arm.com
205110802Srene.dejong@arm.com/**
205210802Srene.dejong@arm.com * SSDisk write done
205310802Srene.dejong@arm.com */
205410802Srene.dejong@arm.com
205510802Srene.dejong@arm.comvoid
205610802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDWriteDone()
205710802Srene.dejong@arm.com{
205810802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write disk, aiming for %d messages, %d so far\n",
205910802Srene.dejong@arm.com            totalWrite, amountOfWriteTransfers);
206010802Srene.dejong@arm.com
206110802Srene.dejong@arm.com    //we have done one extra transfer
206210802Srene.dejong@arm.com    ++amountOfWriteTransfers;
206310802Srene.dejong@arm.com
206410802Srene.dejong@arm.com    /**test whether call was correct*/
206510802Srene.dejong@arm.com    assert(totalWrite >= amountOfWriteTransfers && totalWrite != 0);
206610802Srene.dejong@arm.com
206710802Srene.dejong@arm.com    /**are we there yet? (did we do everything)*/
206810802Srene.dejong@arm.com    if (totalWrite == amountOfWriteTransfers) {
206910802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write transactions finished\n");
207010802Srene.dejong@arm.com        totalWrite = 0;
207110802Srene.dejong@arm.com        amountOfWriteTransfers = 0;
207210802Srene.dejong@arm.com
207310802Srene.dejong@arm.com        //Callback UFS Host
207410802Srene.dejong@arm.com        setSignal();
207510802Srene.dejong@arm.com        signalDone->process();
207610802Srene.dejong@arm.com    }
207710802Srene.dejong@arm.com
207810802Srene.dejong@arm.com}
207910802Srene.dejong@arm.com
208010802Srene.dejong@arm.com/**
208110802Srene.dejong@arm.com * Dma transaction function: read device. Notice that the dma action is from
208210802Srene.dejong@arm.com * a device perspective, while this function is from an initiator perspective
208310802Srene.dejong@arm.com */
208410802Srene.dejong@arm.com
208510802Srene.dejong@arm.comvoid
208610802Srene.dejong@arm.comUFSHostDevice::readDevice(bool lastTransfer, Addr start, uint32_t size,
208710802Srene.dejong@arm.com                          uint8_t* destination, bool no_cache, Event*
208810802Srene.dejong@arm.com                          additional_action)
208910802Srene.dejong@arm.com{
209010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n",
209110802Srene.dejong@arm.com            start, size, (reinterpret_cast<uint32_t *>(destination))[0]);
209210802Srene.dejong@arm.com
209310802Srene.dejong@arm.com    /** check wether interrupt is needed */
209410802Srene.dejong@arm.com    if (lastTransfer) {
209510802Srene.dejong@arm.com        ++readPendingNum;
209612086Sspwilson2@wisc.edu        readDoneEvent.push_back(
209712086Sspwilson2@wisc.edu            EventFunctionWrapper([this]{ readDone(); },
209812086Sspwilson2@wisc.edu                                 name()));
209910802Srene.dejong@arm.com        assert(!readDoneEvent.back().scheduled());
210010802Srene.dejong@arm.com        dmaPort.dmaAction(MemCmd::WriteReq, start, size,
210110802Srene.dejong@arm.com                          &readDoneEvent.back(), destination, 0);
210210802Srene.dejong@arm.com        //yes, a writereq at a read device function is correct.
210310802Srene.dejong@arm.com
210410802Srene.dejong@arm.com    } else {
210510802Srene.dejong@arm.com        if (additional_action != NULL)
210610802Srene.dejong@arm.com            assert(!additional_action->scheduled());
210710802Srene.dejong@arm.com
210810802Srene.dejong@arm.com        dmaPort.dmaAction(MemCmd::WriteReq, start, size,
210910802Srene.dejong@arm.com                          additional_action, destination, 0);
211010802Srene.dejong@arm.com
211110802Srene.dejong@arm.com    }
211210802Srene.dejong@arm.com
211310802Srene.dejong@arm.com}
211410802Srene.dejong@arm.com
211510802Srene.dejong@arm.com/**
211610802Srene.dejong@arm.com * Manage read transfer. Manages correct transfer flow and makes sure that
211710802Srene.dejong@arm.com * the queues are filled on time
211810802Srene.dejong@arm.com */
211910802Srene.dejong@arm.com
212010802Srene.dejong@arm.comvoid
212110802Srene.dejong@arm.comUFSHostDevice::manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t
212210802Srene.dejong@arm.com                                  offset, uint32_t sg_table_length,
212310802Srene.dejong@arm.com                                  struct UFSHCDSGEntry* sglist)
212410802Srene.dejong@arm.com{
212510802Srene.dejong@arm.com    uint32_t size_accum = 0;
212610802Srene.dejong@arm.com
212710802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Data READ size: %d\n", size);
212810802Srene.dejong@arm.com
212910802Srene.dejong@arm.com    /**
213010802Srene.dejong@arm.com     * Break-up the transactions into actions defined by the scatter gather
213110802Srene.dejong@arm.com     * list.
213210802Srene.dejong@arm.com     */
213310802Srene.dejong@arm.com    for (uint32_t count = 0; count < sg_table_length; count++) {
213410802Srene.dejong@arm.com        struct transferInfo new_transfer;
213510802Srene.dejong@arm.com        new_transfer.offset = sglist[count].upperAddr;
213610802Srene.dejong@arm.com        new_transfer.offset = (new_transfer.offset << 32) |
213710802Srene.dejong@arm.com            (sglist[count].baseAddr & 0xFFFFFFFF);
213810802Srene.dejong@arm.com        new_transfer.filePointer = offset + size_accum;
213910802Srene.dejong@arm.com        new_transfer.size = (sglist[count].size + 1);
214010802Srene.dejong@arm.com        new_transfer.lunID = LUN;
214110802Srene.dejong@arm.com
214210802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Data READ start: 0x%8x; size: %d\n",
214310802Srene.dejong@arm.com                new_transfer.offset, new_transfer.size);
214410802Srene.dejong@arm.com
214510802Srene.dejong@arm.com        UFSDevice[LUN]->SSDReadInfo.push_back(new_transfer);
214610802Srene.dejong@arm.com        UFSDevice[LUN]->SSDReadInfo.back().buffer.resize(sglist[count].size
214710802Srene.dejong@arm.com                                                         + 1);
214810802Srene.dejong@arm.com
214910802Srene.dejong@arm.com        /**
215010802Srene.dejong@arm.com         * The disk image is read here; but the action is simultated later
215110802Srene.dejong@arm.com         * You can see this as the preparation stage, whereas later is the
215210802Srene.dejong@arm.com         * simulation phase.
215310802Srene.dejong@arm.com         */
215410802Srene.dejong@arm.com        UFSDevice[LUN]->readFlash(&UFSDevice[LUN]->
215510802Srene.dejong@arm.com                                  SSDReadInfo.back().buffer[0],
215610802Srene.dejong@arm.com                                  offset + size_accum,
215710802Srene.dejong@arm.com                                  sglist[count].size + 1);
215810802Srene.dejong@arm.com
215910802Srene.dejong@arm.com        size_accum += (sglist[count].size + 1);
216010802Srene.dejong@arm.com
216110802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Transfer %d; Remaining: 0x%8x, Accumulated:"
216210802Srene.dejong@arm.com                " 0x%8x\n", (count + 1), (size-size_accum), size_accum);
216310802Srene.dejong@arm.com
216410802Srene.dejong@arm.com        /** stats **/
216510802Srene.dejong@arm.com        stats.totalReadSSD += (sglist[count].size + 1);
216610802Srene.dejong@arm.com        stats.currentReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
216710802Srene.dejong@arm.com        stats.averageReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
216810802Srene.dejong@arm.com    }
216910802Srene.dejong@arm.com
217010802Srene.dejong@arm.com    UFSDevice[LUN]->SSDReadStart(sg_table_length);
217110802Srene.dejong@arm.com
217210802Srene.dejong@arm.com    /** stats **/
217310802Srene.dejong@arm.com    ++stats.totalReadUFSTransactions;
217410802Srene.dejong@arm.com
217510802Srene.dejong@arm.com}
217610802Srene.dejong@arm.com
217710802Srene.dejong@arm.com
217810802Srene.dejong@arm.com
217910802Srene.dejong@arm.com/**
218010802Srene.dejong@arm.com * SSDisk start read; this function was created to keep the interfaces
218110802Srene.dejong@arm.com * between the layers simpler. Without this function UFSHost would need to
218210802Srene.dejong@arm.com * know about the flashdevice.
218310802Srene.dejong@arm.com */
218410802Srene.dejong@arm.com
218510802Srene.dejong@arm.comvoid
218610802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDReadStart(uint32_t total_read)
218710802Srene.dejong@arm.com{
218810802Srene.dejong@arm.com    totalRead = total_read;
218910802Srene.dejong@arm.com    for (uint32_t number_handled = 0; number_handled < SSDReadInfo.size();
219010802Srene.dejong@arm.com         number_handled++) {
219110802Srene.dejong@arm.com        /**
219210802Srene.dejong@arm.com         * Load all the read request to the Memory device.
219310802Srene.dejong@arm.com         * It will call back when done.
219410802Srene.dejong@arm.com         */
219510802Srene.dejong@arm.com        flashDevice->readMemory(SSDReadInfo.front().filePointer,
219610802Srene.dejong@arm.com                                SSDReadInfo.front().size, memReadCallback);
219710802Srene.dejong@arm.com    }
219810802Srene.dejong@arm.com
219910802Srene.dejong@arm.com}
220010802Srene.dejong@arm.com
220110802Srene.dejong@arm.com
220210802Srene.dejong@arm.com/**
220310802Srene.dejong@arm.com * SSDisk read done
220410802Srene.dejong@arm.com */
220510802Srene.dejong@arm.com
220610802Srene.dejong@arm.comvoid
220710802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDReadDone()
220810802Srene.dejong@arm.com{
220910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SSD read done at lun %d, Aiming for %d messages,"
221010802Srene.dejong@arm.com            " %d so far\n", lunID, totalRead, amountOfReadTransfers);
221110802Srene.dejong@arm.com
221210802Srene.dejong@arm.com    if (totalRead == amountOfReadTransfers) {
221310802Srene.dejong@arm.com        totalRead = 0;
221410802Srene.dejong@arm.com        amountOfReadTransfers = 0;
221510802Srene.dejong@arm.com
221610802Srene.dejong@arm.com        /**Callback: transferdone*/
221710802Srene.dejong@arm.com        setSignal();
221810802Srene.dejong@arm.com        signalDone->process();
221910802Srene.dejong@arm.com    }
222010802Srene.dejong@arm.com
222110802Srene.dejong@arm.com}
222210802Srene.dejong@arm.com
222310802Srene.dejong@arm.com/**
222410802Srene.dejong@arm.com * Read callback, on the way from the disk to the DMA. Called by the flash
222510802Srene.dejong@arm.com * layer. Intermediate step to the host layer
222610802Srene.dejong@arm.com */
222710802Srene.dejong@arm.comvoid
222810802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::readCallback()
222910802Srene.dejong@arm.com{
223010802Srene.dejong@arm.com    ++amountOfReadTransfers;
223110802Srene.dejong@arm.com
223210802Srene.dejong@arm.com    /**Callback; make sure data is transfered upstream:
223310802Srene.dejong@arm.com     * UFSHostDevice::readCallback
223410802Srene.dejong@arm.com     */
223510802Srene.dejong@arm.com    setReadSignal();
223610802Srene.dejong@arm.com    deviceReadCallback->process();
223710802Srene.dejong@arm.com
223810802Srene.dejong@arm.com    //Are we done yet?
223910802Srene.dejong@arm.com    SSDReadDone();
224010802Srene.dejong@arm.com}
224110802Srene.dejong@arm.com
224210802Srene.dejong@arm.com/**
224310802Srene.dejong@arm.com * Read callback, on the way from the disk to the DMA. Called by the UFSSCSI
224410802Srene.dejong@arm.com * layer.
224510802Srene.dejong@arm.com */
224610802Srene.dejong@arm.com
224710802Srene.dejong@arm.comvoid
224810802Srene.dejong@arm.comUFSHostDevice::readCallback()
224910802Srene.dejong@arm.com{
225010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Read Callback\n");
225110802Srene.dejong@arm.com    uint8_t this_lun = 0;
225210802Srene.dejong@arm.com
225310802Srene.dejong@arm.com    //while we haven't found the right lun, keep searching
225411321Ssteve.reinhardt@amd.com    while ((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedRead())
225510802Srene.dejong@arm.com        ++this_lun;
225610802Srene.dejong@arm.com
225710802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Found LUN %d messages pending for clean: %d\n",
225810802Srene.dejong@arm.com            this_lun, SSDReadPending.size());
225910802Srene.dejong@arm.com
226010802Srene.dejong@arm.com    if (this_lun < lunAvail) {
226110802Srene.dejong@arm.com        //Clear signal.
226210802Srene.dejong@arm.com        UFSDevice[this_lun]->clearReadSignal();
226310802Srene.dejong@arm.com        SSDReadPending.push_back(UFSDevice[this_lun]->SSDReadInfo.front());
226410802Srene.dejong@arm.com        UFSDevice[this_lun]->SSDReadInfo.pop_front();
226512087Sspwilson2@wisc.edu        readGarbageEventQueue.push_back(
226612087Sspwilson2@wisc.edu            EventFunctionWrapper([this]{ readGarbage(); }, name()));
226710802Srene.dejong@arm.com
226810802Srene.dejong@arm.com        //make sure the queue is popped a the end of the dma transaction
226910802Srene.dejong@arm.com        readDevice(false, SSDReadPending.front().offset,
227010802Srene.dejong@arm.com                   SSDReadPending.front().size,
227110802Srene.dejong@arm.com                   &SSDReadPending.front().buffer[0], false,
227210802Srene.dejong@arm.com                   &readGarbageEventQueue.back());
227310802Srene.dejong@arm.com
227410802Srene.dejong@arm.com        /**stats*/
227510802Srene.dejong@arm.com        ++stats.totalReadDiskTransactions;
227610802Srene.dejong@arm.com    }
227710802Srene.dejong@arm.com    else
227810802Srene.dejong@arm.com        panic("no read finished in tick %d\n", curTick());
227910802Srene.dejong@arm.com}
228010802Srene.dejong@arm.com
228110802Srene.dejong@arm.com/**
228210802Srene.dejong@arm.com * After a disk read DMA transfer, the structure needs to be freed. This is
228310802Srene.dejong@arm.com * done in this function.
228410802Srene.dejong@arm.com */
228510802Srene.dejong@arm.comvoid
228610802Srene.dejong@arm.comUFSHostDevice::readGarbage()
228710802Srene.dejong@arm.com{
228810802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Clean read data, %d\n", SSDReadPending.size());
228910802Srene.dejong@arm.com    SSDReadPending.pop_front();
229010802Srene.dejong@arm.com    readGarbageEventQueue.pop_front();
229110802Srene.dejong@arm.com}
229210802Srene.dejong@arm.com
229310802Srene.dejong@arm.com/**
229410802Srene.dejong@arm.com * Serialize; needed to make checkpoints
229510802Srene.dejong@arm.com */
229610802Srene.dejong@arm.com
229710802Srene.dejong@arm.comvoid
229810905Sandreas.sandberg@arm.comUFSHostDevice::serialize(CheckpointOut &cp) const
229910802Srene.dejong@arm.com{
230010905Sandreas.sandberg@arm.com    DmaDevice::serialize(cp);
230110905Sandreas.sandberg@arm.com
230210905Sandreas.sandberg@arm.com    const uint8_t* temp_HCI_mem = reinterpret_cast<const uint8_t*>(&UFSHCIMem);
230310802Srene.dejong@arm.com    SERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
230410802Srene.dejong@arm.com
230510802Srene.dejong@arm.com    uint32_t lun_avail = lunAvail;
230610802Srene.dejong@arm.com    SERIALIZE_SCALAR(lun_avail);
230710802Srene.dejong@arm.com}
230810802Srene.dejong@arm.com
230910802Srene.dejong@arm.com
231010802Srene.dejong@arm.com/**
231110802Srene.dejong@arm.com * Unserialize; needed to restore from checkpoints
231210802Srene.dejong@arm.com */
231310802Srene.dejong@arm.com
231410802Srene.dejong@arm.comvoid
231510905Sandreas.sandberg@arm.comUFSHostDevice::unserialize(CheckpointIn &cp)
231610802Srene.dejong@arm.com{
231710905Sandreas.sandberg@arm.com    DmaDevice::unserialize(cp);
231810802Srene.dejong@arm.com    uint8_t* temp_HCI_mem = reinterpret_cast<uint8_t*>(&UFSHCIMem);
231910802Srene.dejong@arm.com    UNSERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
232010802Srene.dejong@arm.com
232110802Srene.dejong@arm.com    uint32_t lun_avail;
232210802Srene.dejong@arm.com    UNSERIALIZE_SCALAR(lun_avail);
232310802Srene.dejong@arm.com    assert(lunAvail == lun_avail);
232410802Srene.dejong@arm.com}
232510802Srene.dejong@arm.com
232610802Srene.dejong@arm.com
232710802Srene.dejong@arm.com/**
232810802Srene.dejong@arm.com * Drain; needed to enable checkpoints
232910802Srene.dejong@arm.com */
233010802Srene.dejong@arm.com
233110913Sandreas.sandberg@arm.comDrainState
233210913Sandreas.sandberg@arm.comUFSHostDevice::drain()
233310802Srene.dejong@arm.com{
233410802Srene.dejong@arm.com    if (UFSHCIMem.TRUTRLDBR) {
233510802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "UFSDevice is draining...\n");
233610913Sandreas.sandberg@arm.com        return DrainState::Draining;
233710802Srene.dejong@arm.com    } else {
233810802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "UFSDevice drained\n");
233910913Sandreas.sandberg@arm.com        return DrainState::Drained;
234010802Srene.dejong@arm.com    }
234110802Srene.dejong@arm.com}
234210802Srene.dejong@arm.com
234310802Srene.dejong@arm.com/**
234410802Srene.dejong@arm.com * Checkdrain; needed to enable checkpoints
234510802Srene.dejong@arm.com */
234610802Srene.dejong@arm.com
234710802Srene.dejong@arm.comvoid
234810802Srene.dejong@arm.comUFSHostDevice::checkDrain()
234910802Srene.dejong@arm.com{
235010913Sandreas.sandberg@arm.com    if (drainState() != DrainState::Draining)
235110802Srene.dejong@arm.com        return;
235210802Srene.dejong@arm.com
235310802Srene.dejong@arm.com    if (UFSHCIMem.TRUTRLDBR) {
235410802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "UFSDevice is still draining; with %d active"
235510802Srene.dejong@arm.com            " doorbells\n", activeDoorbells);
235610802Srene.dejong@arm.com    } else {
235710802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "UFSDevice is done draining\n");
235810913Sandreas.sandberg@arm.com        signalDrainDone();
235910802Srene.dejong@arm.com    }
236010802Srene.dejong@arm.com}
2361