ufs_device.cc revision 10913
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;
16410802Srene.dejong@arm.com    memset(&scsi_out, 0, sizeof(struct SCSIReply));
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 */
69610802Srene.dejong@arm.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*/
71010802Srene.dejong@arm.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),
73610802Srene.dejong@arm.com    SCSIResumeEvent(this),
73710802Srene.dejong@arm.com    UTPEvent(this)
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
74810802Srene.dejong@arm.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{
77710802Srene.dejong@arm.com    using namespace Stats;
77810802Srene.dejong@arm.com
77910802Srene.dejong@arm.com    std::string UFSHost_name = name() + ".UFSDiskHost";
78010802Srene.dejong@arm.com
78110802Srene.dejong@arm.com    // Register the stats
78210802Srene.dejong@arm.com    /** Queue lengths */
78310802Srene.dejong@arm.com    stats.currentSCSIQueue
78410802Srene.dejong@arm.com        .name(UFSHost_name + ".currentSCSIQueue")
78510802Srene.dejong@arm.com        .desc("Most up to date length of the command queue")
78610802Srene.dejong@arm.com        .flags(none);
78710802Srene.dejong@arm.com    stats.currentReadSSDQueue
78810802Srene.dejong@arm.com        .name(UFSHost_name + ".currentReadSSDQueue")
78910802Srene.dejong@arm.com        .desc("Most up to date length of the read SSD queue")
79010802Srene.dejong@arm.com        .flags(none);
79110802Srene.dejong@arm.com    stats.currentWriteSSDQueue
79210802Srene.dejong@arm.com        .name(UFSHost_name + ".currentWriteSSDQueue")
79310802Srene.dejong@arm.com        .desc("Most up to date length of the write SSD queue")
79410802Srene.dejong@arm.com        .flags(none);
79510802Srene.dejong@arm.com
79610802Srene.dejong@arm.com    /** Amount of data read/written */
79710802Srene.dejong@arm.com    stats.totalReadSSD
79810802Srene.dejong@arm.com        .name(UFSHost_name + ".totalReadSSD")
79910802Srene.dejong@arm.com        .desc("Number of bytes read from SSD")
80010802Srene.dejong@arm.com        .flags(none);
80110802Srene.dejong@arm.com
80210802Srene.dejong@arm.com    stats.totalWrittenSSD
80310802Srene.dejong@arm.com        .name(UFSHost_name + ".totalWrittenSSD")
80410802Srene.dejong@arm.com        .desc("Number of bytes written to SSD")
80510802Srene.dejong@arm.com        .flags(none);
80610802Srene.dejong@arm.com
80710802Srene.dejong@arm.com    stats.totalReadDiskTransactions
80810802Srene.dejong@arm.com        .name(UFSHost_name + ".totalReadDiskTransactions")
80910802Srene.dejong@arm.com        .desc("Number of transactions from disk")
81010802Srene.dejong@arm.com        .flags(none);
81110802Srene.dejong@arm.com    stats.totalWriteDiskTransactions
81210802Srene.dejong@arm.com        .name(UFSHost_name + ".totalWriteDiskTransactions")
81310802Srene.dejong@arm.com        .desc("Number of transactions to disk")
81410802Srene.dejong@arm.com        .flags(none);
81510802Srene.dejong@arm.com    stats.totalReadUFSTransactions
81610802Srene.dejong@arm.com        .name(UFSHost_name + ".totalReadUFSTransactions")
81710802Srene.dejong@arm.com        .desc("Number of transactions from device")
81810802Srene.dejong@arm.com        .flags(none);
81910802Srene.dejong@arm.com    stats.totalWriteUFSTransactions
82010802Srene.dejong@arm.com        .name(UFSHost_name + ".totalWriteUFSTransactions")
82110802Srene.dejong@arm.com        .desc("Number of transactions to device")
82210802Srene.dejong@arm.com        .flags(none);
82310802Srene.dejong@arm.com
82410802Srene.dejong@arm.com    /** Average bandwidth for reads and writes */
82510802Srene.dejong@arm.com    stats.averageReadSSDBW
82610802Srene.dejong@arm.com        .name(UFSHost_name + ".averageReadSSDBandwidth")
82710802Srene.dejong@arm.com        .desc("Average read bandwidth (bytes/s)")
82810802Srene.dejong@arm.com        .flags(nozero);
82910802Srene.dejong@arm.com
83010802Srene.dejong@arm.com    stats.averageReadSSDBW = stats.totalReadSSD / simSeconds;
83110802Srene.dejong@arm.com
83210802Srene.dejong@arm.com    stats.averageWriteSSDBW
83310802Srene.dejong@arm.com        .name(UFSHost_name + ".averageWriteSSDBandwidth")
83410802Srene.dejong@arm.com        .desc("Average write bandwidth (bytes/s)")
83510802Srene.dejong@arm.com        .flags(nozero);
83610802Srene.dejong@arm.com
83710802Srene.dejong@arm.com    stats.averageWriteSSDBW = stats.totalWrittenSSD / simSeconds;
83810802Srene.dejong@arm.com
83910802Srene.dejong@arm.com    stats.averageSCSIQueue
84010802Srene.dejong@arm.com        .name(UFSHost_name + ".averageSCSIQueueLength")
84110802Srene.dejong@arm.com        .desc("Average command queue length")
84210802Srene.dejong@arm.com        .flags(nozero);
84310802Srene.dejong@arm.com    stats.averageReadSSDQueue
84410802Srene.dejong@arm.com        .name(UFSHost_name + ".averageReadSSDQueueLength")
84510802Srene.dejong@arm.com        .desc("Average read queue length")
84610802Srene.dejong@arm.com        .flags(nozero);
84710802Srene.dejong@arm.com    stats.averageWriteSSDQueue
84810802Srene.dejong@arm.com        .name(UFSHost_name + ".averageWriteSSDQueueLength")
84910802Srene.dejong@arm.com        .desc("Average write queue length")
85010802Srene.dejong@arm.com        .flags(nozero);
85110802Srene.dejong@arm.com
85210802Srene.dejong@arm.com    /** Number of doorbells rung*/
85310802Srene.dejong@arm.com    stats.curDoorbell
85410802Srene.dejong@arm.com        .name(UFSHost_name + ".curDoorbell")
85510802Srene.dejong@arm.com        .desc("Most up to date number of doorbells used")
85610802Srene.dejong@arm.com        .flags(none);
85710802Srene.dejong@arm.com
85810802Srene.dejong@arm.com    stats.curDoorbell = activeDoorbells;
85910802Srene.dejong@arm.com
86010802Srene.dejong@arm.com    stats.maxDoorbell
86110802Srene.dejong@arm.com        .name(UFSHost_name + ".maxDoorbell")
86210802Srene.dejong@arm.com        .desc("Maximum number of doorbells utilized")
86310802Srene.dejong@arm.com        .flags(none);
86410802Srene.dejong@arm.com    stats.averageDoorbell
86510802Srene.dejong@arm.com        .name(UFSHost_name + ".averageDoorbell")
86610802Srene.dejong@arm.com        .desc("Average number of Doorbells used")
86710802Srene.dejong@arm.com        .flags(nozero);
86810802Srene.dejong@arm.com
86910802Srene.dejong@arm.com    /** Latency*/
87010802Srene.dejong@arm.com    stats.transactionLatency
87110802Srene.dejong@arm.com        .init(100)
87210802Srene.dejong@arm.com        .name(UFSHost_name + ".transactionLatency")
87310802Srene.dejong@arm.com        .desc("Histogram of transaction times")
87410802Srene.dejong@arm.com        .flags(pdf);
87510802Srene.dejong@arm.com
87610802Srene.dejong@arm.com    stats.idleTimes
87710802Srene.dejong@arm.com        .init(100)
87810802Srene.dejong@arm.com        .name(UFSHost_name + ".idlePeriods")
87910802Srene.dejong@arm.com        .desc("Histogram of idle times")
88010802Srene.dejong@arm.com        .flags(pdf);
88110802Srene.dejong@arm.com
88210802Srene.dejong@arm.com}
88310802Srene.dejong@arm.com
88410802Srene.dejong@arm.com/**
88510802Srene.dejong@arm.com * Register init
88610802Srene.dejong@arm.com */
88710802Srene.dejong@arm.comvoid UFSHostDevice::setValues()
88810802Srene.dejong@arm.com{
88910802Srene.dejong@arm.com    /**
89010802Srene.dejong@arm.com     * The capability register is built up as follows:
89110802Srene.dejong@arm.com     * 31-29 RES; Testmode support; O3 delivery; 64 bit addr;
89210802Srene.dejong@arm.com     * 23-19 RES; 18-16 #TM Req slots; 15-5 RES;4-0 # TR slots
89310802Srene.dejong@arm.com     */
89410802Srene.dejong@arm.com    UFSHCIMem.HCCAP = 0x06070000 | (UFSSlots & 0x1F);
89510802Srene.dejong@arm.com    UFSHCIMem.HCversion = 0x00010000; //version is 1.0
89610802Srene.dejong@arm.com    UFSHCIMem.HCHCDDID = 0xAA003C3C;// Arbitrary number
89710802Srene.dejong@arm.com    UFSHCIMem.HCHCPMID = 0x41524D48; //ARMH (not an official MIPI number)
89810802Srene.dejong@arm.com    UFSHCIMem.TRUTRLDBR = 0x00;
89910802Srene.dejong@arm.com    UFSHCIMem.TMUTMRLDBR = 0x00;
90010802Srene.dejong@arm.com    UFSHCIMem.CMDUICCMDR = 0x00;
90110802Srene.dejong@arm.com    // We can process CMD, TM, TR, device present
90210802Srene.dejong@arm.com    UFSHCIMem.ORHostControllerStatus = 0x08;
90310802Srene.dejong@arm.com    UFSHCIMem.TRUTRLBA = 0x00;
90410802Srene.dejong@arm.com    UFSHCIMem.TRUTRLBAU = 0x00;
90510802Srene.dejong@arm.com    UFSHCIMem.TMUTMRLBA = 0x00;
90610802Srene.dejong@arm.com    UFSHCIMem.TMUTMRLBAU = 0x00;
90710802Srene.dejong@arm.com}
90810802Srene.dejong@arm.com
90910802Srene.dejong@arm.com/**
91010802Srene.dejong@arm.com * Determine address ranges
91110802Srene.dejong@arm.com */
91210802Srene.dejong@arm.com
91310802Srene.dejong@arm.comAddrRangeList
91410802Srene.dejong@arm.comUFSHostDevice::getAddrRanges() const
91510802Srene.dejong@arm.com{
91610802Srene.dejong@arm.com    AddrRangeList ranges;
91710802Srene.dejong@arm.com    ranges.push_back(RangeSize(pioAddr, pioSize));
91810802Srene.dejong@arm.com    return ranges;
91910802Srene.dejong@arm.com}
92010802Srene.dejong@arm.com
92110802Srene.dejong@arm.com/**
92210802Srene.dejong@arm.com * UFSHCD read register. This function allows the system to read the
92310802Srene.dejong@arm.com * register entries
92410802Srene.dejong@arm.com */
92510802Srene.dejong@arm.com
92610802Srene.dejong@arm.comTick
92710802Srene.dejong@arm.comUFSHostDevice::read(PacketPtr pkt)
92810802Srene.dejong@arm.com{
92910802Srene.dejong@arm.com    uint32_t data = 0;
93010802Srene.dejong@arm.com
93110802Srene.dejong@arm.com    switch (pkt->getAddr() & 0xFF)
93210802Srene.dejong@arm.com    {
93310802Srene.dejong@arm.com
93410802Srene.dejong@arm.com      case regControllerCapabilities:
93510802Srene.dejong@arm.com        data = UFSHCIMem.HCCAP;
93610802Srene.dejong@arm.com        break;
93710802Srene.dejong@arm.com
93810802Srene.dejong@arm.com      case regUFSVersion:
93910802Srene.dejong@arm.com        data = UFSHCIMem.HCversion;
94010802Srene.dejong@arm.com        break;
94110802Srene.dejong@arm.com
94210802Srene.dejong@arm.com      case regControllerDEVID:
94310802Srene.dejong@arm.com        data = UFSHCIMem.HCHCDDID;
94410802Srene.dejong@arm.com        break;
94510802Srene.dejong@arm.com
94610802Srene.dejong@arm.com      case regControllerPRODID:
94710802Srene.dejong@arm.com        data = UFSHCIMem.HCHCPMID;
94810802Srene.dejong@arm.com        break;
94910802Srene.dejong@arm.com
95010802Srene.dejong@arm.com      case regInterruptStatus:
95110802Srene.dejong@arm.com        data = UFSHCIMem.ORInterruptStatus;
95210802Srene.dejong@arm.com        UFSHCIMem.ORInterruptStatus = 0x00;
95310802Srene.dejong@arm.com        //TODO: Revise and extend
95410802Srene.dejong@arm.com        clearInterrupt();
95510802Srene.dejong@arm.com        break;
95610802Srene.dejong@arm.com
95710802Srene.dejong@arm.com      case regInterruptEnable:
95810802Srene.dejong@arm.com        data = UFSHCIMem.ORInterruptEnable;
95910802Srene.dejong@arm.com        break;
96010802Srene.dejong@arm.com
96110802Srene.dejong@arm.com      case regControllerStatus:
96210802Srene.dejong@arm.com        data = UFSHCIMem.ORHostControllerStatus;
96310802Srene.dejong@arm.com        break;
96410802Srene.dejong@arm.com
96510802Srene.dejong@arm.com      case regControllerEnable:
96610802Srene.dejong@arm.com        data = UFSHCIMem.ORHostControllerEnable;
96710802Srene.dejong@arm.com        break;
96810802Srene.dejong@arm.com
96910802Srene.dejong@arm.com      case regUICErrorCodePHYAdapterLayer:
97010802Srene.dejong@arm.com        data = UFSHCIMem.ORUECPA;
97110802Srene.dejong@arm.com        break;
97210802Srene.dejong@arm.com
97310802Srene.dejong@arm.com      case regUICErrorCodeDataLinkLayer:
97410802Srene.dejong@arm.com        data = UFSHCIMem.ORUECDL;
97510802Srene.dejong@arm.com        break;
97610802Srene.dejong@arm.com
97710802Srene.dejong@arm.com      case regUICErrorCodeNetworkLayer:
97810802Srene.dejong@arm.com        data = UFSHCIMem.ORUECN;
97910802Srene.dejong@arm.com        break;
98010802Srene.dejong@arm.com
98110802Srene.dejong@arm.com      case regUICErrorCodeTransportLayer:
98210802Srene.dejong@arm.com        data = UFSHCIMem.ORUECT;
98310802Srene.dejong@arm.com        break;
98410802Srene.dejong@arm.com
98510802Srene.dejong@arm.com      case regUICErrorCodeDME:
98610802Srene.dejong@arm.com        data = UFSHCIMem.ORUECDME;
98710802Srene.dejong@arm.com        break;
98810802Srene.dejong@arm.com
98910802Srene.dejong@arm.com      case regUTPTransferREQINTAGGControl:
99010802Srene.dejong@arm.com        data = UFSHCIMem.ORUTRIACR;
99110802Srene.dejong@arm.com        break;
99210802Srene.dejong@arm.com
99310802Srene.dejong@arm.com      case regUTPTransferREQListBaseL:
99410802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLBA;
99510802Srene.dejong@arm.com        break;
99610802Srene.dejong@arm.com
99710802Srene.dejong@arm.com      case regUTPTransferREQListBaseH:
99810802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLBAU;
99910802Srene.dejong@arm.com        break;
100010802Srene.dejong@arm.com
100110802Srene.dejong@arm.com      case regUTPTransferREQDoorbell:
100210802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLDBR;
100310802Srene.dejong@arm.com        break;
100410802Srene.dejong@arm.com
100510802Srene.dejong@arm.com      case regUTPTransferREQListClear:
100610802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLCLR;
100710802Srene.dejong@arm.com        break;
100810802Srene.dejong@arm.com
100910802Srene.dejong@arm.com      case regUTPTransferREQListRunStop:
101010802Srene.dejong@arm.com        data = UFSHCIMem.TRUTRLRSR;
101110802Srene.dejong@arm.com        break;
101210802Srene.dejong@arm.com
101310802Srene.dejong@arm.com      case regUTPTaskREQListBaseL:
101410802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLBA;
101510802Srene.dejong@arm.com        break;
101610802Srene.dejong@arm.com
101710802Srene.dejong@arm.com      case regUTPTaskREQListBaseH:
101810802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLBAU;
101910802Srene.dejong@arm.com        break;
102010802Srene.dejong@arm.com
102110802Srene.dejong@arm.com      case regUTPTaskREQDoorbell:
102210802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLDBR;
102310802Srene.dejong@arm.com        break;
102410802Srene.dejong@arm.com
102510802Srene.dejong@arm.com      case regUTPTaskREQListClear:
102610802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLCLR;
102710802Srene.dejong@arm.com        break;
102810802Srene.dejong@arm.com
102910802Srene.dejong@arm.com      case regUTPTaskREQListRunStop:
103010802Srene.dejong@arm.com        data = UFSHCIMem.TMUTMRLRSR;
103110802Srene.dejong@arm.com        break;
103210802Srene.dejong@arm.com
103310802Srene.dejong@arm.com      case regUICCommand:
103410802Srene.dejong@arm.com        data = UFSHCIMem.CMDUICCMDR;
103510802Srene.dejong@arm.com        break;
103610802Srene.dejong@arm.com
103710802Srene.dejong@arm.com      case regUICCommandArg1:
103810802Srene.dejong@arm.com        data = UFSHCIMem.CMDUCMDARG1;
103910802Srene.dejong@arm.com        break;
104010802Srene.dejong@arm.com
104110802Srene.dejong@arm.com      case regUICCommandArg2:
104210802Srene.dejong@arm.com        data = UFSHCIMem.CMDUCMDARG2;
104310802Srene.dejong@arm.com        break;
104410802Srene.dejong@arm.com
104510802Srene.dejong@arm.com      case regUICCommandArg3:
104610802Srene.dejong@arm.com        data = UFSHCIMem.CMDUCMDARG3;
104710802Srene.dejong@arm.com        break;
104810802Srene.dejong@arm.com
104910802Srene.dejong@arm.com      default:
105010802Srene.dejong@arm.com        data = 0x00;
105110802Srene.dejong@arm.com        break;
105210802Srene.dejong@arm.com    }
105310802Srene.dejong@arm.com
105410802Srene.dejong@arm.com    pkt->set<uint32_t>(data);
105510802Srene.dejong@arm.com    pkt->makeResponse();
105610802Srene.dejong@arm.com    return pioDelay;
105710802Srene.dejong@arm.com}
105810802Srene.dejong@arm.com
105910802Srene.dejong@arm.com/**
106010802Srene.dejong@arm.com * UFSHCD write function. This function allows access to the writeable
106110802Srene.dejong@arm.com * registers. If any function attempts to write value to an unwriteable
106210802Srene.dejong@arm.com * register entry, then the value will not be written.
106310802Srene.dejong@arm.com */
106410802Srene.dejong@arm.comTick
106510802Srene.dejong@arm.comUFSHostDevice::write(PacketPtr pkt)
106610802Srene.dejong@arm.com{
106710802Srene.dejong@arm.com    uint32_t data = 0;
106810802Srene.dejong@arm.com
106910802Srene.dejong@arm.com    switch (pkt->getSize()) {
107010802Srene.dejong@arm.com
107110802Srene.dejong@arm.com      case 1:
107210802Srene.dejong@arm.com        data = pkt->get<uint8_t>();
107310802Srene.dejong@arm.com        break;
107410802Srene.dejong@arm.com
107510802Srene.dejong@arm.com      case 2:
107610802Srene.dejong@arm.com        data = pkt->get<uint16_t>();
107710802Srene.dejong@arm.com        break;
107810802Srene.dejong@arm.com
107910802Srene.dejong@arm.com      case 4:
108010802Srene.dejong@arm.com        data = pkt->get<uint32_t>();
108110802Srene.dejong@arm.com        break;
108210802Srene.dejong@arm.com
108310802Srene.dejong@arm.com      default:
108410802Srene.dejong@arm.com        panic("Undefined UFSHCD controller write size!\n");
108510802Srene.dejong@arm.com        break;
108610802Srene.dejong@arm.com    }
108710802Srene.dejong@arm.com
108810802Srene.dejong@arm.com    switch (pkt->getAddr() & 0xFF)
108910802Srene.dejong@arm.com    {
109010802Srene.dejong@arm.com      case regControllerCapabilities://you shall not write to this
109110802Srene.dejong@arm.com        break;
109210802Srene.dejong@arm.com
109310802Srene.dejong@arm.com      case regUFSVersion://you shall not write to this
109410802Srene.dejong@arm.com        break;
109510802Srene.dejong@arm.com
109610802Srene.dejong@arm.com      case regControllerDEVID://you shall not write to this
109710802Srene.dejong@arm.com        break;
109810802Srene.dejong@arm.com
109910802Srene.dejong@arm.com      case regControllerPRODID://you shall not write to this
110010802Srene.dejong@arm.com        break;
110110802Srene.dejong@arm.com
110210802Srene.dejong@arm.com      case regInterruptStatus://you shall not write to this
110310802Srene.dejong@arm.com        break;
110410802Srene.dejong@arm.com
110510802Srene.dejong@arm.com      case regInterruptEnable:
110610802Srene.dejong@arm.com        UFSHCIMem.ORInterruptEnable = data;
110710802Srene.dejong@arm.com        break;
110810802Srene.dejong@arm.com
110910802Srene.dejong@arm.com      case regControllerStatus:
111010802Srene.dejong@arm.com        UFSHCIMem.ORHostControllerStatus = data;
111110802Srene.dejong@arm.com        break;
111210802Srene.dejong@arm.com
111310802Srene.dejong@arm.com      case regControllerEnable:
111410802Srene.dejong@arm.com        UFSHCIMem.ORHostControllerEnable = data;
111510802Srene.dejong@arm.com        break;
111610802Srene.dejong@arm.com
111710802Srene.dejong@arm.com      case regUICErrorCodePHYAdapterLayer:
111810802Srene.dejong@arm.com        UFSHCIMem.ORUECPA = data;
111910802Srene.dejong@arm.com        break;
112010802Srene.dejong@arm.com
112110802Srene.dejong@arm.com      case regUICErrorCodeDataLinkLayer:
112210802Srene.dejong@arm.com        UFSHCIMem.ORUECDL = data;
112310802Srene.dejong@arm.com        break;
112410802Srene.dejong@arm.com
112510802Srene.dejong@arm.com      case regUICErrorCodeNetworkLayer:
112610802Srene.dejong@arm.com        UFSHCIMem.ORUECN = data;
112710802Srene.dejong@arm.com        break;
112810802Srene.dejong@arm.com
112910802Srene.dejong@arm.com      case regUICErrorCodeTransportLayer:
113010802Srene.dejong@arm.com        UFSHCIMem.ORUECT = data;
113110802Srene.dejong@arm.com        break;
113210802Srene.dejong@arm.com
113310802Srene.dejong@arm.com      case regUICErrorCodeDME:
113410802Srene.dejong@arm.com        UFSHCIMem.ORUECDME = data;
113510802Srene.dejong@arm.com        break;
113610802Srene.dejong@arm.com
113710802Srene.dejong@arm.com      case regUTPTransferREQINTAGGControl:
113810802Srene.dejong@arm.com        UFSHCIMem.ORUTRIACR = data;
113910802Srene.dejong@arm.com        break;
114010802Srene.dejong@arm.com
114110802Srene.dejong@arm.com      case regUTPTransferREQListBaseL:
114210802Srene.dejong@arm.com        UFSHCIMem.TRUTRLBA = data;
114310802Srene.dejong@arm.com        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
114410802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU)!= 0x00))
114510802Srene.dejong@arm.com            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
114610802Srene.dejong@arm.com        break;
114710802Srene.dejong@arm.com
114810802Srene.dejong@arm.com      case regUTPTransferREQListBaseH:
114910802Srene.dejong@arm.com        UFSHCIMem.TRUTRLBAU = data;
115010802Srene.dejong@arm.com        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
115110802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
115210802Srene.dejong@arm.com            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
115310802Srene.dejong@arm.com        break;
115410802Srene.dejong@arm.com
115510802Srene.dejong@arm.com      case regUTPTransferREQDoorbell:
115610802Srene.dejong@arm.com        if (!(UFSHCIMem.TRUTRLDBR) && data)
115710802Srene.dejong@arm.com            stats.idleTimes.sample(curTick() - idlePhaseStart);
115810802Srene.dejong@arm.com        UFSHCIMem.TRUTRLDBR |= data;
115910802Srene.dejong@arm.com        requestHandler();
116010802Srene.dejong@arm.com        break;
116110802Srene.dejong@arm.com
116210802Srene.dejong@arm.com      case regUTPTransferREQListClear:
116310802Srene.dejong@arm.com        UFSHCIMem.TRUTRLCLR = data;
116410802Srene.dejong@arm.com        break;
116510802Srene.dejong@arm.com
116610802Srene.dejong@arm.com      case regUTPTransferREQListRunStop:
116710802Srene.dejong@arm.com        UFSHCIMem.TRUTRLRSR = data;
116810802Srene.dejong@arm.com        break;
116910802Srene.dejong@arm.com
117010802Srene.dejong@arm.com      case regUTPTaskREQListBaseL:
117110802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLBA = data;
117210802Srene.dejong@arm.com        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
117310802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
117410802Srene.dejong@arm.com            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
117510802Srene.dejong@arm.com        break;
117610802Srene.dejong@arm.com
117710802Srene.dejong@arm.com      case regUTPTaskREQListBaseH:
117810802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLBAU = data;
117910802Srene.dejong@arm.com        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
118010802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
118110802Srene.dejong@arm.com            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
118210802Srene.dejong@arm.com        break;
118310802Srene.dejong@arm.com
118410802Srene.dejong@arm.com      case regUTPTaskREQDoorbell:
118510802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLDBR |= data;
118610802Srene.dejong@arm.com        requestHandler();
118710802Srene.dejong@arm.com        break;
118810802Srene.dejong@arm.com
118910802Srene.dejong@arm.com      case regUTPTaskREQListClear:
119010802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLCLR = data;
119110802Srene.dejong@arm.com        break;
119210802Srene.dejong@arm.com
119310802Srene.dejong@arm.com      case regUTPTaskREQListRunStop:
119410802Srene.dejong@arm.com        UFSHCIMem.TMUTMRLRSR = data;
119510802Srene.dejong@arm.com        break;
119610802Srene.dejong@arm.com
119710802Srene.dejong@arm.com      case regUICCommand:
119810802Srene.dejong@arm.com        UFSHCIMem.CMDUICCMDR = data;
119910802Srene.dejong@arm.com        requestHandler();
120010802Srene.dejong@arm.com        break;
120110802Srene.dejong@arm.com
120210802Srene.dejong@arm.com      case regUICCommandArg1:
120310802Srene.dejong@arm.com        UFSHCIMem.CMDUCMDARG1 = data;
120410802Srene.dejong@arm.com        break;
120510802Srene.dejong@arm.com
120610802Srene.dejong@arm.com      case regUICCommandArg2:
120710802Srene.dejong@arm.com        UFSHCIMem.CMDUCMDARG2 = data;
120810802Srene.dejong@arm.com        break;
120910802Srene.dejong@arm.com
121010802Srene.dejong@arm.com      case regUICCommandArg3:
121110802Srene.dejong@arm.com        UFSHCIMem.CMDUCMDARG3 = data;
121210802Srene.dejong@arm.com        break;
121310802Srene.dejong@arm.com
121410802Srene.dejong@arm.com      default:break;//nothing happens, you try to access a register that
121510802Srene.dejong@arm.com                    //does not exist
121610802Srene.dejong@arm.com
121710802Srene.dejong@arm.com    }
121810802Srene.dejong@arm.com
121910802Srene.dejong@arm.com    pkt->makeResponse();
122010802Srene.dejong@arm.com    return pioDelay;
122110802Srene.dejong@arm.com}
122210802Srene.dejong@arm.com
122310802Srene.dejong@arm.com/**
122410802Srene.dejong@arm.com * Request handler. Determines where the request comes from and initiates the
122510802Srene.dejong@arm.com * appropriate actions accordingly.
122610802Srene.dejong@arm.com */
122710802Srene.dejong@arm.com
122810802Srene.dejong@arm.comvoid
122910802Srene.dejong@arm.comUFSHostDevice::requestHandler()
123010802Srene.dejong@arm.com{
123110802Srene.dejong@arm.com    Addr address = 0x00;
123210802Srene.dejong@arm.com    int mask = 0x01;
123310802Srene.dejong@arm.com    int size;
123410802Srene.dejong@arm.com    int count = 0;
123510802Srene.dejong@arm.com    struct taskStart task_info;
123610802Srene.dejong@arm.com    struct transferStart transferstart_info;
123710802Srene.dejong@arm.com    transferstart_info.done = 0;
123810802Srene.dejong@arm.com
123910802Srene.dejong@arm.com    /**
124010802Srene.dejong@arm.com     * step1 determine what called us
124110802Srene.dejong@arm.com     * step2 determine where to get it
124210802Srene.dejong@arm.com     * Look for any request of which we where not yet aware
124310802Srene.dejong@arm.com     */
124410802Srene.dejong@arm.com    while (((UFSHCIMem.CMDUICCMDR > 0x00) |
124510802Srene.dejong@arm.com            ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) |
124610802Srene.dejong@arm.com            ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00)) ) {
124710802Srene.dejong@arm.com
124810802Srene.dejong@arm.com        if (UFSHCIMem.CMDUICCMDR > 0x00) {
124910802Srene.dejong@arm.com            /**
125010802Srene.dejong@arm.com             * Command; general control of the Host controller.
125110802Srene.dejong@arm.com             * no DMA transfer needed
125210802Srene.dejong@arm.com             */
125310802Srene.dejong@arm.com            commandHandler();
125410802Srene.dejong@arm.com            UFSHCIMem.ORInterruptStatus |= UICCommandCOMPL;
125510802Srene.dejong@arm.com            generateInterrupt();
125610802Srene.dejong@arm.com            UFSHCIMem.CMDUICCMDR = 0x00;
125710802Srene.dejong@arm.com            return; //command, nothing more we can do
125810802Srene.dejong@arm.com
125910802Srene.dejong@arm.com        } else if ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) {
126010802Srene.dejong@arm.com            /**
126110802Srene.dejong@arm.com             * Task; flow control, meant for the device/Logic unit
126210802Srene.dejong@arm.com             * DMA transfer is needed, flash will not be approached
126310802Srene.dejong@arm.com             */
126410802Srene.dejong@arm.com            size = sizeof(UTPUPIUTaskReq);
126510802Srene.dejong@arm.com            /**Find the position that is not handled yet*/
126610802Srene.dejong@arm.com            count = findLsbSet((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack));
126710802Srene.dejong@arm.com            address = UFSHCIMem.TMUTMRLBAU;
126810802Srene.dejong@arm.com            //<-64 bit
126910802Srene.dejong@arm.com            address = (count * size) + (address << 32) +
127010802Srene.dejong@arm.com                UFSHCIMem.TMUTMRLBA;
127110802Srene.dejong@arm.com            taskCommandTrack |= mask << count;
127210802Srene.dejong@arm.com
127310802Srene.dejong@arm.com            inform("UFSmodel received a task from the system; this might"
127410802Srene.dejong@arm.com                   " lead to untested behaviour.\n");
127510802Srene.dejong@arm.com
127610802Srene.dejong@arm.com            task_info.mask = mask << count;
127710802Srene.dejong@arm.com            task_info.address = address;
127810802Srene.dejong@arm.com            task_info.size = size;
127910802Srene.dejong@arm.com            task_info.done = UFSHCIMem.TMUTMRLDBR;
128010802Srene.dejong@arm.com            taskInfo.push_back(task_info);
128110802Srene.dejong@arm.com            taskEventQueue.push_back(this);
128210802Srene.dejong@arm.com            writeDevice(&taskEventQueue.back(), false, address, size,
128310802Srene.dejong@arm.com                        reinterpret_cast<uint8_t*>
128410802Srene.dejong@arm.com                        (&taskInfo.back().destination), 0, 0);
128510802Srene.dejong@arm.com
128610802Srene.dejong@arm.com        } else if ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00) {
128710802Srene.dejong@arm.com            /**
128810802Srene.dejong@arm.com             * Transfer; Data transfer from or to the disk. There will be DMA
128910802Srene.dejong@arm.com             * transfers, and the flash might be approached. Further
129010802Srene.dejong@arm.com             * commands, are needed to specify the exact command.
129110802Srene.dejong@arm.com             */
129210802Srene.dejong@arm.com            size = sizeof(UTPTransferReqDesc);
129310802Srene.dejong@arm.com            /**Find the position that is not handled yet*/
129410802Srene.dejong@arm.com            count = findLsbSet((UFSHCIMem.TRUTRLDBR ^ transferTrack));
129510802Srene.dejong@arm.com            address = UFSHCIMem.TRUTRLBAU;
129610802Srene.dejong@arm.com            //<-64 bit
129710802Srene.dejong@arm.com            address = (count * size) + (address << 32) + UFSHCIMem.TRUTRLBA;
129810802Srene.dejong@arm.com
129910802Srene.dejong@arm.com            transferTrack |= mask << count;
130010802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Doorbell register: 0x%8x select #:"
130110802Srene.dejong@arm.com                    " 0x%8x completion info: 0x%8x\n", UFSHCIMem.TRUTRLDBR,
130210802Srene.dejong@arm.com                    count, transferstart_info.done);
130310802Srene.dejong@arm.com
130410802Srene.dejong@arm.com            transferstart_info.done = UFSHCIMem.TRUTRLDBR;
130510802Srene.dejong@arm.com
130610802Srene.dejong@arm.com            /**stats**/
130710802Srene.dejong@arm.com            transactionStart[count] = curTick(); //note the start time
130810802Srene.dejong@arm.com            ++activeDoorbells;
130910802Srene.dejong@arm.com            stats.maxDoorbell = (stats.maxDoorbell.value() < activeDoorbells)
131010802Srene.dejong@arm.com                ? activeDoorbells : stats.maxDoorbell.value();
131110802Srene.dejong@arm.com            stats.averageDoorbell = stats.maxDoorbell.value();
131210802Srene.dejong@arm.com
131310802Srene.dejong@arm.com            /**
131410802Srene.dejong@arm.com             * step3 start transfer
131510802Srene.dejong@arm.com             * step4 register information; allowing the host to respond in
131610802Srene.dejong@arm.com             * the end
131710802Srene.dejong@arm.com             */
131810802Srene.dejong@arm.com            transferstart_info.mask = mask << count;
131910802Srene.dejong@arm.com            transferstart_info.address = address;
132010802Srene.dejong@arm.com            transferstart_info.size = size;
132110802Srene.dejong@arm.com            transferstart_info.done = UFSHCIMem.TRUTRLDBR;
132210802Srene.dejong@arm.com            transferStartInfo.push_back(transferstart_info);
132310802Srene.dejong@arm.com
132410802Srene.dejong@arm.com            /**Deleted in readDone, queued in finalUTP*/
132510802Srene.dejong@arm.com            transferStartInfo.back().destination = new struct
132610802Srene.dejong@arm.com                UTPTransferReqDesc;
132710802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Initial transfer start: 0x%8x\n",
132810802Srene.dejong@arm.com                    transferstart_info.done);
132910802Srene.dejong@arm.com            transferEventQueue.push_back(this);
133010802Srene.dejong@arm.com
133110802Srene.dejong@arm.com            if (transferEventQueue.size() < 2) {
133210802Srene.dejong@arm.com                writeDevice(&transferEventQueue.front(), false,
133310802Srene.dejong@arm.com                            address, size, reinterpret_cast<uint8_t*>
133410802Srene.dejong@arm.com                            (transferStartInfo.front().destination),0, 0);
133510802Srene.dejong@arm.com                DPRINTF(UFSHostDevice, "Transfer scheduled\n");
133610802Srene.dejong@arm.com            }
133710802Srene.dejong@arm.com        }
133810802Srene.dejong@arm.com    }
133910802Srene.dejong@arm.com}
134010802Srene.dejong@arm.com
134110802Srene.dejong@arm.com/**
134210802Srene.dejong@arm.com * Task start event
134310802Srene.dejong@arm.com */
134410802Srene.dejong@arm.com
134510802Srene.dejong@arm.comvoid
134610802Srene.dejong@arm.comUFSHostDevice::taskStart()
134710802Srene.dejong@arm.com{
134810802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Task start");
134910802Srene.dejong@arm.com    taskHandler(&taskInfo.front().destination, taskInfo.front().mask,
135010802Srene.dejong@arm.com                taskInfo.front().address, taskInfo.front().size);
135110802Srene.dejong@arm.com    taskInfo.pop_front();
135210802Srene.dejong@arm.com    taskEventQueue.pop_front();
135310802Srene.dejong@arm.com}
135410802Srene.dejong@arm.com
135510802Srene.dejong@arm.com/**
135610802Srene.dejong@arm.com * Transfer start event
135710802Srene.dejong@arm.com */
135810802Srene.dejong@arm.com
135910802Srene.dejong@arm.comvoid
136010802Srene.dejong@arm.comUFSHostDevice::transferStart()
136110802Srene.dejong@arm.com{
136210802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Enter transfer event\n");
136310802Srene.dejong@arm.com    transferHandler(transferStartInfo.front().destination,
136410802Srene.dejong@arm.com                    transferStartInfo.front().mask,
136510802Srene.dejong@arm.com                    transferStartInfo.front().address,
136610802Srene.dejong@arm.com                    transferStartInfo.front().size,
136710802Srene.dejong@arm.com                    transferStartInfo.front().done);
136810802Srene.dejong@arm.com
136910802Srene.dejong@arm.com    transferStartInfo.pop_front();
137010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Transfer queue size at end of event: "
137110802Srene.dejong@arm.com            "0x%8x\n", transferEventQueue.size());
137210802Srene.dejong@arm.com}
137310802Srene.dejong@arm.com
137410802Srene.dejong@arm.com/**
137510802Srene.dejong@arm.com * Handles the commands that are given. At this point in time, not many
137610802Srene.dejong@arm.com * commands have been implemented in the driver.
137710802Srene.dejong@arm.com */
137810802Srene.dejong@arm.com
137910802Srene.dejong@arm.comvoid
138010802Srene.dejong@arm.comUFSHostDevice::commandHandler()
138110802Srene.dejong@arm.com{
138210802Srene.dejong@arm.com    if (UFSHCIMem.CMDUICCMDR == 0x16) {
138310802Srene.dejong@arm.com        UFSHCIMem.ORHostControllerStatus |= 0x0F;//link startup
138410802Srene.dejong@arm.com    }
138510802Srene.dejong@arm.com
138610802Srene.dejong@arm.com}
138710802Srene.dejong@arm.com
138810802Srene.dejong@arm.com/**
138910802Srene.dejong@arm.com * Handles the tasks that are given. At this point in time, not many tasks
139010802Srene.dejong@arm.com * have been implemented in the driver.
139110802Srene.dejong@arm.com */
139210802Srene.dejong@arm.com
139310802Srene.dejong@arm.comvoid
139410802Srene.dejong@arm.comUFSHostDevice::taskHandler(struct UTPUPIUTaskReq* request_in,
139510802Srene.dejong@arm.com                           uint32_t req_pos, Addr finaladdress, uint32_t
139610802Srene.dejong@arm.com                           finalsize)
139710802Srene.dejong@arm.com{
139810802Srene.dejong@arm.com    /**
139910802Srene.dejong@arm.com     * For now, just unpack and acknowledge the task without doing anything.
140010802Srene.dejong@arm.com     * TODO Implement UFS tasks.
140110802Srene.dejong@arm.com     */
140210802Srene.dejong@arm.com    inform("taskHandler\n");
140310802Srene.dejong@arm.com    inform("%8x\n", request_in->header.dWord0);
140410802Srene.dejong@arm.com    inform("%8x\n", request_in->header.dWord1);
140510802Srene.dejong@arm.com    inform("%8x\n", request_in->header.dWord2);
140610802Srene.dejong@arm.com
140710802Srene.dejong@arm.com    request_in->header.dWord2 &= 0xffffff00;
140810802Srene.dejong@arm.com
140910802Srene.dejong@arm.com    UFSHCIMem.TMUTMRLDBR &= ~(req_pos);
141010802Srene.dejong@arm.com    taskCommandTrack &= ~(req_pos);
141110802Srene.dejong@arm.com    UFSHCIMem.ORInterruptStatus |= UTPTaskREQCOMPL;
141210802Srene.dejong@arm.com
141310802Srene.dejong@arm.com    readDevice(true, finaladdress, finalsize, reinterpret_cast<uint8_t*>
141410802Srene.dejong@arm.com               (request_in), true, NULL);
141510802Srene.dejong@arm.com
141610802Srene.dejong@arm.com}
141710802Srene.dejong@arm.com
141810802Srene.dejong@arm.com/**
141910802Srene.dejong@arm.com * Obtains the SCSI command (if any)
142010802Srene.dejong@arm.com * Two possibilities: if it contains a SCSI command, then it is a usable
142110802Srene.dejong@arm.com * message; if it doesnt contain a SCSI message, then it can't be handeld
142210802Srene.dejong@arm.com * by this code.
142310802Srene.dejong@arm.com * This is the second stage of the transfer. We have the information about
142410802Srene.dejong@arm.com * where the next command can be found and what the type of command is. The
142510802Srene.dejong@arm.com * actions that are needed from the device its side are: get the information
142610802Srene.dejong@arm.com * and store the information such that we can reply.
142710802Srene.dejong@arm.com */
142810802Srene.dejong@arm.com
142910802Srene.dejong@arm.comvoid
143010802Srene.dejong@arm.comUFSHostDevice::transferHandler(struct UTPTransferReqDesc* request_in,
143110802Srene.dejong@arm.com                               int req_pos, Addr finaladdress, uint32_t
143210802Srene.dejong@arm.com                               finalsize, uint32_t done)
143310802Srene.dejong@arm.com{
143410802Srene.dejong@arm.com
143510802Srene.dejong@arm.com    Addr cmd_desc_addr = 0x00;
143610802Srene.dejong@arm.com
143710802Srene.dejong@arm.com
143810802Srene.dejong@arm.com    //acknowledge handling of the message
143910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI message detected\n");
144010802Srene.dejong@arm.com    request_in->header.dWord2 &= 0xffffff00;
144110802Srene.dejong@arm.com    SCSIInfo.RequestIn = request_in;
144210802Srene.dejong@arm.com    SCSIInfo.reqPos = req_pos;
144310802Srene.dejong@arm.com    SCSIInfo.finalAddress = finaladdress;
144410802Srene.dejong@arm.com    SCSIInfo.finalSize = finalsize;
144510802Srene.dejong@arm.com    SCSIInfo.destination.resize(request_in->PRDTableOffset * 4
144610802Srene.dejong@arm.com        + request_in->PRDTableLength * sizeof(UFSHCDSGEntry));
144710802Srene.dejong@arm.com    SCSIInfo.done = done;
144810802Srene.dejong@arm.com
144910802Srene.dejong@arm.com    assert(!SCSIResumeEvent.scheduled());
145010802Srene.dejong@arm.com    /**
145110802Srene.dejong@arm.com     *Get the UTP command that has the SCSI command
145210802Srene.dejong@arm.com     */
145310802Srene.dejong@arm.com    cmd_desc_addr = request_in->commandDescBaseAddrHi;
145410802Srene.dejong@arm.com    cmd_desc_addr = (cmd_desc_addr << 32) |
145510802Srene.dejong@arm.com        (request_in->commandDescBaseAddrLo & 0xffffffff);
145610802Srene.dejong@arm.com
145710802Srene.dejong@arm.com    writeDevice(&SCSIResumeEvent, false, cmd_desc_addr,
145810802Srene.dejong@arm.com                SCSIInfo.destination.size(), &SCSIInfo.destination[0],0, 0);
145910802Srene.dejong@arm.com
146010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI scheduled\n");
146110802Srene.dejong@arm.com
146210802Srene.dejong@arm.com    transferEventQueue.pop_front();
146310802Srene.dejong@arm.com}
146410802Srene.dejong@arm.com
146510802Srene.dejong@arm.com/**
146610802Srene.dejong@arm.com * Obtain LUN and put it in the right LUN queue. Each LUN has its own queue
146710802Srene.dejong@arm.com * of commands that need to be executed. This is the first instance where it
146810802Srene.dejong@arm.com * can be determined which Logic unit should handle the transfer. Then check
146910802Srene.dejong@arm.com * wether it should wait and queue or if it can continue.
147010802Srene.dejong@arm.com */
147110802Srene.dejong@arm.com
147210802Srene.dejong@arm.comvoid
147310802Srene.dejong@arm.comUFSHostDevice::SCSIStart()
147410802Srene.dejong@arm.com{
147510802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI message on hold until ready\n");
147610802Srene.dejong@arm.com    uint32_t LUN = SCSIInfo.destination[2];
147710802Srene.dejong@arm.com    UFSDevice[LUN]->SCSIInfoQueue.push_back(SCSIInfo);
147810802Srene.dejong@arm.com
147910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI queue %d has %d elements\n", LUN,
148010802Srene.dejong@arm.com            UFSDevice[LUN]->SCSIInfoQueue.size());
148110802Srene.dejong@arm.com
148210802Srene.dejong@arm.com    /**There are 32 doorbells, so at max there can be 32 transactions*/
148310802Srene.dejong@arm.com    if (UFSDevice[LUN]->SCSIInfoQueue.size() < 2) //LUN is available
148410802Srene.dejong@arm.com        SCSIResume(LUN);
148510802Srene.dejong@arm.com
148610802Srene.dejong@arm.com    else if (UFSDevice[LUN]->SCSIInfoQueue.size() > 32)
148710802Srene.dejong@arm.com        panic("SCSI queue is getting too big %d\n", UFSDevice[LUN]->
148810802Srene.dejong@arm.com              SCSIInfoQueue.size());
148910802Srene.dejong@arm.com
149010802Srene.dejong@arm.com    /**
149110802Srene.dejong@arm.com     * First transfer is done, fetch the next;
149210802Srene.dejong@arm.com     * At this point, the device is busy, not the HC
149310802Srene.dejong@arm.com     */
149410802Srene.dejong@arm.com    if (!transferEventQueue.empty()) {
149510802Srene.dejong@arm.com
149610802Srene.dejong@arm.com        /**
149710802Srene.dejong@arm.com         * loading next data packet in case Another LUN
149810802Srene.dejong@arm.com         * is approached in the mean time
149910802Srene.dejong@arm.com         */
150010802Srene.dejong@arm.com        writeDevice(&transferEventQueue.front(), false,
150110802Srene.dejong@arm.com                    transferStartInfo.front().address,
150210802Srene.dejong@arm.com                    transferStartInfo.front().size, reinterpret_cast<uint8_t*>
150310802Srene.dejong@arm.com                    (transferStartInfo.front().destination), 0, 0);
150410802Srene.dejong@arm.com
150510802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Transfer scheduled");
150610802Srene.dejong@arm.com    }
150710802Srene.dejong@arm.com}
150810802Srene.dejong@arm.com
150910802Srene.dejong@arm.com/**
151010802Srene.dejong@arm.com * Handles the transfer requests that are given.
151110802Srene.dejong@arm.com * There can be three types of transfer. SCSI specific, Reads and writes
151210802Srene.dejong@arm.com * apart from the data transfer, this also generates its own reply (UPIU
151310802Srene.dejong@arm.com * response). Information for this reply is stored in transferInfo and will
151410802Srene.dejong@arm.com * be used in transferDone
151510802Srene.dejong@arm.com */
151610802Srene.dejong@arm.com
151710802Srene.dejong@arm.comvoid
151810802Srene.dejong@arm.comUFSHostDevice::SCSIResume(uint32_t lun_id)
151910802Srene.dejong@arm.com{
152010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSIresume\n");
152110802Srene.dejong@arm.com    if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
152210802Srene.dejong@arm.com        panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
152310802Srene.dejong@arm.com              UFSHCIMem.TRUTRLDBR);
152410802Srene.dejong@arm.com
152510802Srene.dejong@arm.com    /**old info, lets form it such that we can understand it*/
152610802Srene.dejong@arm.com    struct UTPTransferReqDesc* request_in = UFSDevice[lun_id]->
152710802Srene.dejong@arm.com        SCSIInfoQueue.front().RequestIn;
152810802Srene.dejong@arm.com
152910802Srene.dejong@arm.com    uint32_t req_pos = UFSDevice[lun_id]->SCSIInfoQueue.front().reqPos;
153010802Srene.dejong@arm.com
153110802Srene.dejong@arm.com    Addr finaladdress = UFSDevice[lun_id]->SCSIInfoQueue.front().
153210802Srene.dejong@arm.com        finalAddress;
153310802Srene.dejong@arm.com
153410802Srene.dejong@arm.com    uint32_t finalsize = UFSDevice[lun_id]->SCSIInfoQueue.front().finalSize;
153510802Srene.dejong@arm.com
153610802Srene.dejong@arm.com    uint32_t* transfercommand = reinterpret_cast<uint32_t*>
153710802Srene.dejong@arm.com        (&(UFSDevice[lun_id]->SCSIInfoQueue.front().destination[0]));
153810802Srene.dejong@arm.com
153910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Task tag: 0x%8x\n", transfercommand[0]>>24);
154010802Srene.dejong@arm.com    /**call logic unit to handle SCSI command*/
154110802Srene.dejong@arm.com    request_out_datain = UFSDevice[(transfercommand[0] & 0xFF0000) >> 16]->
154210802Srene.dejong@arm.com        SCSICMDHandle(transfercommand);
154310802Srene.dejong@arm.com
154410802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "LUN: %d\n", request_out_datain.LUN);
154510802Srene.dejong@arm.com
154610802Srene.dejong@arm.com    /**
154710802Srene.dejong@arm.com     * build response stating that it was succesful
154810802Srene.dejong@arm.com     * command completion, Logic unit number, and Task tag
154910802Srene.dejong@arm.com     */
155010802Srene.dejong@arm.com    request_in->header.dWord0 = ((request_in->header.dWord0 >> 24) == 0x21)
155110802Srene.dejong@arm.com        ? 0x36 : 0x21;
155210802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord0 =
155310802Srene.dejong@arm.com        request_in->header.dWord0 | (request_out_datain.LUN << 8)
155410802Srene.dejong@arm.com        | (transfercommand[0] & 0xFF000000);
155510802Srene.dejong@arm.com    /**SCSI status reply*/
155610802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord1 = 0x00000000 |
155710802Srene.dejong@arm.com        (request_out_datain.status << 24);
155810802Srene.dejong@arm.com    /**segment size + EHS length (see UFS standard ch7)*/
155910802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord2 = 0x00000000 |
156010802Srene.dejong@arm.com        ((request_out_datain.senseSize + 2) << 24) | 0x05;
156110802Srene.dejong@arm.com    /**amount of data that will follow*/
156210802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.requestOut.senseDataLen =
156310802Srene.dejong@arm.com        request_out_datain.senseSize;
156410802Srene.dejong@arm.com
156510802Srene.dejong@arm.com    //data
156610802Srene.dejong@arm.com    for (uint8_t count = 0; count<request_out_datain.senseSize; count++) {
156710802Srene.dejong@arm.com        UFSDevice[lun_id]->transferInfo.requestOut.senseData[count] =
156810802Srene.dejong@arm.com            request_out_datain.senseCode[count + 1];
156910802Srene.dejong@arm.com    }
157010802Srene.dejong@arm.com
157110802Srene.dejong@arm.com    /*
157210802Srene.dejong@arm.com     * At position defined by "request_in->PRDTableOffset" (counting 32 bit
157310802Srene.dejong@arm.com     * words) in array "transfercommand" we have a scatter gather list, which
157410802Srene.dejong@arm.com     * is usefull to us if we interpreted it as a UFSHCDSGEntry structure.
157510802Srene.dejong@arm.com     */
157610802Srene.dejong@arm.com    struct UFSHCDSGEntry* sglist =  reinterpret_cast<UFSHCDSGEntry*>
157710802Srene.dejong@arm.com        (&(transfercommand[(request_in->PRDTableOffset)]));
157810802Srene.dejong@arm.com
157910802Srene.dejong@arm.com    uint32_t length = request_in->PRDTableLength;
158010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "# PRDT entries: %d\n", length);
158110802Srene.dejong@arm.com
158210802Srene.dejong@arm.com    Addr response_addr = request_in->commandDescBaseAddrHi;
158310802Srene.dejong@arm.com    response_addr = (response_addr << 32) |
158410802Srene.dejong@arm.com        ((request_in->commandDescBaseAddrLo +
158510802Srene.dejong@arm.com          (request_in->responseUPIULength << 2)) & 0xffffffff);
158610802Srene.dejong@arm.com
158710802Srene.dejong@arm.com    /**transferdone information packet filling*/
158810802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.responseStartAddr = response_addr;
158910802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.reqPos = req_pos;
159010802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.size = finalsize;
159110802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.address = finaladdress;
159210802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.destination = reinterpret_cast<uint8_t*>
159310802Srene.dejong@arm.com        (UFSDevice[lun_id]->SCSIInfoQueue.front().RequestIn);
159410802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.finished = true;
159510802Srene.dejong@arm.com    UFSDevice[lun_id]->transferInfo.lunID = request_out_datain.LUN;
159610802Srene.dejong@arm.com
159710802Srene.dejong@arm.com    /**
159810802Srene.dejong@arm.com     * In this part the data that needs to be transfered will be initiated
159910802Srene.dejong@arm.com     * and the chain of DMA (and potentially) disk transactions will be
160010802Srene.dejong@arm.com     * started.
160110802Srene.dejong@arm.com     */
160210802Srene.dejong@arm.com    if (request_out_datain.expectMore == 0x01) {
160310802Srene.dejong@arm.com        /**write transfer*/
160410802Srene.dejong@arm.com        manageWriteTransfer(request_out_datain.LUN, request_out_datain.offset,
160510802Srene.dejong@arm.com                            length, sglist);
160610802Srene.dejong@arm.com
160710802Srene.dejong@arm.com    } else if (request_out_datain.expectMore == 0x02) {
160810802Srene.dejong@arm.com        /**read transfer*/
160910802Srene.dejong@arm.com        manageReadTransfer(request_out_datain.msgSize, request_out_datain.LUN,
161010802Srene.dejong@arm.com                           request_out_datain.offset, length, sglist);
161110802Srene.dejong@arm.com
161210802Srene.dejong@arm.com    } else {
161310802Srene.dejong@arm.com        /**not disk related transfer, SCSI maintanance*/
161410802Srene.dejong@arm.com        uint32_t count = 0;
161510802Srene.dejong@arm.com        uint32_t size_accum = 0;
161610802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
161710802Srene.dejong@arm.com                request_out_datain.msgSize);
161810802Srene.dejong@arm.com
161910802Srene.dejong@arm.com        /**Transport the SCSI reponse data according to the SG list*/
162010802Srene.dejong@arm.com        while ((length > count) && size_accum
162110802Srene.dejong@arm.com               < (request_out_datain.msgSize - 1) &&
162210802Srene.dejong@arm.com               (request_out_datain.msgSize != 0x00)) {
162310802Srene.dejong@arm.com            Addr SCSI_start = sglist[count].upperAddr;
162410802Srene.dejong@arm.com            SCSI_start = (SCSI_start << 32) |
162510802Srene.dejong@arm.com                (sglist[count].baseAddr & 0xFFFFFFFF);
162610802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Data DMA start: 0x%8x\n", SCSI_start);
162710802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
162810802Srene.dejong@arm.com                    (sglist[count].size + 1));
162910802Srene.dejong@arm.com            /**
163010802Srene.dejong@arm.com             * safetynet; it has been shown that sg list may be optimistic in
163110802Srene.dejong@arm.com             * the amount of data allocated, which can potentially lead to
163210802Srene.dejong@arm.com             * some garbage data being send over. Hence this construction
163310802Srene.dejong@arm.com             * that finds the least amount of data that needs to be
163410802Srene.dejong@arm.com             * transfered.
163510802Srene.dejong@arm.com             */
163610802Srene.dejong@arm.com            uint32_t size_to_send = sglist[count].size + 1;
163710802Srene.dejong@arm.com
163810802Srene.dejong@arm.com            if (request_out_datain.msgSize < (size_to_send + size_accum))
163910802Srene.dejong@arm.com                size_to_send = request_out_datain.msgSize - size_accum;
164010802Srene.dejong@arm.com
164110802Srene.dejong@arm.com            readDevice(false, SCSI_start, size_to_send,
164210802Srene.dejong@arm.com                       reinterpret_cast<uint8_t*>
164310802Srene.dejong@arm.com                       (&(request_out_datain.message.dataMsg[size_accum])),
164410802Srene.dejong@arm.com                       false, NULL);
164510802Srene.dejong@arm.com
164610802Srene.dejong@arm.com            size_accum += size_to_send;
164710802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Total remaining: 0x%8x,accumulated so far"
164810802Srene.dejong@arm.com                    " : 0x%8x\n", (request_out_datain.msgSize - size_accum),
164910802Srene.dejong@arm.com                    size_accum);
165010802Srene.dejong@arm.com
165110802Srene.dejong@arm.com            ++count;
165210802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Transfer #: %d\n", count);
165310802Srene.dejong@arm.com        }
165410802Srene.dejong@arm.com
165510802Srene.dejong@arm.com        /**Go to the next stage of the answering process*/
165610802Srene.dejong@arm.com        transferDone(response_addr, req_pos, UFSDevice[lun_id]->
165710802Srene.dejong@arm.com                     transferInfo.requestOut, finalsize, finaladdress,
165810802Srene.dejong@arm.com                     reinterpret_cast<uint8_t*>(request_in), true, lun_id);
165910802Srene.dejong@arm.com    }
166010802Srene.dejong@arm.com
166110802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSI resume done\n");
166210802Srene.dejong@arm.com}
166310802Srene.dejong@arm.com
166410802Srene.dejong@arm.com/**
166510802Srene.dejong@arm.com * Find finished transfer. Callback function. One of the LUNs is done with
166610802Srene.dejong@arm.com * the disk transfer and reports back to the controller. This function finds
166710802Srene.dejong@arm.com * out who it was, and calls transferDone.
166810802Srene.dejong@arm.com */
166910802Srene.dejong@arm.comvoid
167010802Srene.dejong@arm.comUFSHostDevice::LUNSignal()
167110802Srene.dejong@arm.com{
167210802Srene.dejong@arm.com    uint8_t this_lun = 0;
167310802Srene.dejong@arm.com
167410802Srene.dejong@arm.com    //while we haven't found the right lun, keep searching
167510802Srene.dejong@arm.com    while((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedCommand())
167610802Srene.dejong@arm.com        ++this_lun;
167710802Srene.dejong@arm.com
167810802Srene.dejong@arm.com    if (this_lun < lunAvail) {
167910802Srene.dejong@arm.com        //Clear signal.
168010802Srene.dejong@arm.com        UFSDevice[this_lun]->clearSignal();
168110802Srene.dejong@arm.com        //found it; call transferDone
168210802Srene.dejong@arm.com        transferDone(UFSDevice[this_lun]->transferInfo.responseStartAddr,
168310802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.reqPos,
168410802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.requestOut,
168510802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.size,
168610802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.address,
168710802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.destination,
168810802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.finished,
168910802Srene.dejong@arm.com                     UFSDevice[this_lun]->transferInfo.lunID);
169010802Srene.dejong@arm.com    }
169110802Srene.dejong@arm.com
169210802Srene.dejong@arm.com    else
169310802Srene.dejong@arm.com        panic("no LUN finished in tick %d\n", curTick());
169410802Srene.dejong@arm.com}
169510802Srene.dejong@arm.com
169610802Srene.dejong@arm.com/**
169710802Srene.dejong@arm.com * Transfer done. When the data transfer is done, this function ensures
169810802Srene.dejong@arm.com * that the application is notified.
169910802Srene.dejong@arm.com */
170010802Srene.dejong@arm.com
170110802Srene.dejong@arm.comvoid
170210802Srene.dejong@arm.comUFSHostDevice::transferDone(Addr responseStartAddr, uint32_t req_pos,
170310802Srene.dejong@arm.com                            struct UTPUPIURSP request_out, uint32_t size,
170410802Srene.dejong@arm.com                            Addr address, uint8_t* destination,
170510802Srene.dejong@arm.com                            bool finished, uint32_t lun_id)
170610802Srene.dejong@arm.com{
170710802Srene.dejong@arm.com    /**Test whether SCSI queue hasn't popped prematurely*/
170810802Srene.dejong@arm.com    if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
170910802Srene.dejong@arm.com        panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
171010802Srene.dejong@arm.com              UFSHCIMem.TRUTRLDBR);
171110802Srene.dejong@arm.com
171210802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "DMA start: 0x%8x; DMA size: 0x%8x\n",
171310802Srene.dejong@arm.com            responseStartAddr, sizeof(request_out));
171410802Srene.dejong@arm.com
171510802Srene.dejong@arm.com    struct transferStart lastinfo;
171610802Srene.dejong@arm.com    lastinfo.mask = req_pos;
171710802Srene.dejong@arm.com    lastinfo.done = finished;
171810802Srene.dejong@arm.com    lastinfo.address = address;
171910802Srene.dejong@arm.com    lastinfo.size = size;
172010802Srene.dejong@arm.com    lastinfo.destination = reinterpret_cast<UTPTransferReqDesc*>
172110802Srene.dejong@arm.com        (destination);
172210802Srene.dejong@arm.com    lastinfo.lun_id = lun_id;
172310802Srene.dejong@arm.com
172410802Srene.dejong@arm.com    transferEnd.push_back(lastinfo);
172510802Srene.dejong@arm.com
172610802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Transfer done start\n");
172710802Srene.dejong@arm.com
172810802Srene.dejong@arm.com    readDevice(false, responseStartAddr, sizeof(request_out),
172910802Srene.dejong@arm.com               reinterpret_cast<uint8_t*>
173010802Srene.dejong@arm.com               (&(UFSDevice[lun_id]->transferInfo.requestOut)),
173110802Srene.dejong@arm.com               true, &UTPEvent);
173210802Srene.dejong@arm.com}
173310802Srene.dejong@arm.com
173410802Srene.dejong@arm.com/**
173510802Srene.dejong@arm.com * finalUTP. Second part of the transfer done event.
173610802Srene.dejong@arm.com * this sends the final response: the UTP response. After this transaction
173710802Srene.dejong@arm.com * the doorbell shall be cleared, and the interupt shall be set.
173810802Srene.dejong@arm.com */
173910802Srene.dejong@arm.com
174010802Srene.dejong@arm.comvoid
174110802Srene.dejong@arm.comUFSHostDevice::finalUTP()
174210802Srene.dejong@arm.com{
174310802Srene.dejong@arm.com    uint32_t lun_id = transferEnd.front().lun_id;
174410802Srene.dejong@arm.com
174510802Srene.dejong@arm.com    UFSDevice[lun_id]->SCSIInfoQueue.pop_front();
174610802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SCSIInfoQueue size: %d, lun: %d\n",
174710802Srene.dejong@arm.com            UFSDevice[lun_id]->SCSIInfoQueue.size(), lun_id);
174810802Srene.dejong@arm.com
174910802Srene.dejong@arm.com    /**stats**/
175010802Srene.dejong@arm.com    if (UFSHCIMem.TRUTRLDBR & transferEnd.front().mask) {
175110802Srene.dejong@arm.com        uint8_t count = 0;
175210802Srene.dejong@arm.com        while (!(transferEnd.front().mask & (0x1 << count)))
175310802Srene.dejong@arm.com            ++count;
175410802Srene.dejong@arm.com        stats.transactionLatency.sample(curTick() -
175510802Srene.dejong@arm.com                                        transactionStart[count]);
175610802Srene.dejong@arm.com    }
175710802Srene.dejong@arm.com
175810802Srene.dejong@arm.com    /**Last message that will be transfered*/
175910802Srene.dejong@arm.com    readDevice(true, transferEnd.front().address,
176010802Srene.dejong@arm.com               transferEnd.front().size, reinterpret_cast<uint8_t*>
176110802Srene.dejong@arm.com               (transferEnd.front().destination), true, NULL);
176210802Srene.dejong@arm.com
176310802Srene.dejong@arm.com    /**clean and ensure that the tracker is updated*/
176410802Srene.dejong@arm.com    transferTrack &= ~(transferEnd.front().mask);
176510802Srene.dejong@arm.com    --activeDoorbells;
176610802Srene.dejong@arm.com    ++pendingDoorbells;
176710802Srene.dejong@arm.com    garbage.push_back(transferEnd.front().destination);
176810802Srene.dejong@arm.com    transferEnd.pop_front();
176910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "UTP handled\n");
177010802Srene.dejong@arm.com
177110802Srene.dejong@arm.com    /**stats**/
177210802Srene.dejong@arm.com    stats.averageDoorbell = stats.maxDoorbell.value();
177310802Srene.dejong@arm.com
177410802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "activeDoorbells: %d, pendingDoorbells: %d,"
177510802Srene.dejong@arm.com            " garbage: %d, TransferEvent: %d\n", activeDoorbells,
177610802Srene.dejong@arm.com            pendingDoorbells, garbage.size(), transferEventQueue.size());
177710802Srene.dejong@arm.com
177810802Srene.dejong@arm.com    /**This is the moment that the device is available again*/
177910802Srene.dejong@arm.com    if (!UFSDevice[lun_id]->SCSIInfoQueue.empty())
178010802Srene.dejong@arm.com        SCSIResume(lun_id);
178110802Srene.dejong@arm.com}
178210802Srene.dejong@arm.com
178310802Srene.dejong@arm.com/**
178410802Srene.dejong@arm.com * Read done handling function, is only initiated at the end of a transaction
178510802Srene.dejong@arm.com */
178610802Srene.dejong@arm.comvoid
178710802Srene.dejong@arm.comUFSHostDevice::readDone()
178810802Srene.dejong@arm.com{
178910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Read done start\n");
179010802Srene.dejong@arm.com    --readPendingNum;
179110802Srene.dejong@arm.com
179210802Srene.dejong@arm.com    /**Garbage collection; sort out the allocated UTP descriptor*/
179310802Srene.dejong@arm.com    if (garbage.size() > 0) {
179410802Srene.dejong@arm.com        delete garbage.front();
179510802Srene.dejong@arm.com        garbage.pop_front();
179610802Srene.dejong@arm.com        }
179710802Srene.dejong@arm.com
179810802Srene.dejong@arm.com    /**done, generate interrupt if we havent got one already*/
179910802Srene.dejong@arm.com    if(!(UFSHCIMem.ORInterruptStatus & 0x01)) {
180010802Srene.dejong@arm.com        UFSHCIMem.ORInterruptStatus |= UTPTransferREQCOMPL;
180110802Srene.dejong@arm.com        generateInterrupt();
180210802Srene.dejong@arm.com    }
180310802Srene.dejong@arm.com
180410802Srene.dejong@arm.com
180510802Srene.dejong@arm.com    if(!readDoneEvent.empty()) {
180610802Srene.dejong@arm.com        readDoneEvent.pop_front();
180710802Srene.dejong@arm.com    }
180810802Srene.dejong@arm.com}
180910802Srene.dejong@arm.com
181010802Srene.dejong@arm.com/**
181110802Srene.dejong@arm.com * set interrupt and sort out the doorbell register.
181210802Srene.dejong@arm.com */
181310802Srene.dejong@arm.com
181410802Srene.dejong@arm.comvoid
181510802Srene.dejong@arm.comUFSHostDevice::generateInterrupt()
181610802Srene.dejong@arm.com{
181710802Srene.dejong@arm.com    /**just to keep track of the transactions*/
181810802Srene.dejong@arm.com    countInt++;
181910802Srene.dejong@arm.com
182010802Srene.dejong@arm.com    /**step5 clear doorbell*/
182110802Srene.dejong@arm.com    UFSHCIMem.TRUTRLDBR &= transferTrack;
182210802Srene.dejong@arm.com    pendingDoorbells = 0;
182310802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Clear doorbell %X\n", UFSHCIMem.TRUTRLDBR);
182410802Srene.dejong@arm.com
182510802Srene.dejong@arm.com    /**step6 raise interrupt*/
182610802Srene.dejong@arm.com    gic->sendInt(intNum);
182710802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Send interrupt @ transaction: 0x%8x!\n",
182810802Srene.dejong@arm.com            countInt);
182910802Srene.dejong@arm.com}
183010802Srene.dejong@arm.com
183110802Srene.dejong@arm.com/**
183210802Srene.dejong@arm.com * Clear interrupt
183310802Srene.dejong@arm.com */
183410802Srene.dejong@arm.com
183510802Srene.dejong@arm.comvoid
183610802Srene.dejong@arm.comUFSHostDevice::clearInterrupt()
183710802Srene.dejong@arm.com{
183810802Srene.dejong@arm.com    gic->clearInt(intNum);
183910802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Clear interrupt: 0x%8x!\n", countInt);
184010802Srene.dejong@arm.com
184110802Srene.dejong@arm.com    if (!(UFSHCIMem.TRUTRLDBR)) {
184210802Srene.dejong@arm.com        idlePhaseStart = curTick();
184310802Srene.dejong@arm.com    }
184410802Srene.dejong@arm.com    /**end of a transaction*/
184510802Srene.dejong@arm.com}
184610802Srene.dejong@arm.com
184710802Srene.dejong@arm.com/**
184810802Srene.dejong@arm.com * Important to understand about the transfer flow:
184910802Srene.dejong@arm.com * We have basically three stages, The "system memory" stage, the "device
185010802Srene.dejong@arm.com * buffer" stage and the "disk" stage. In this model we assume an infinite
185110802Srene.dejong@arm.com * buffer, or a buffer that is big enough to store all the data in the
185210802Srene.dejong@arm.com * biggest transaction. Between the three stages are two queues. Those queues
185310802Srene.dejong@arm.com * store the messages to simulate their transaction from one stage to the
185410802Srene.dejong@arm.com * next. The manage{Action} function fills up one of the queues and triggers
185510802Srene.dejong@arm.com * the first event, which causes a chain reaction of events executed once
185610802Srene.dejong@arm.com * they pass through their queues. For a write action the stages are ordered
185710802Srene.dejong@arm.com * "system memory", "device buffer" and "disk", whereas the read transfers
185810802Srene.dejong@arm.com * happen "disk", "device buffer" and "system memory". The dma action in the
185910802Srene.dejong@arm.com * dma device is written from a bus perspective whereas this model is written
186010802Srene.dejong@arm.com * from a device perspective. To avoid confusion, the translation between the
186110802Srene.dejong@arm.com * two has been made in the writeDevice and readDevice funtions.
186210802Srene.dejong@arm.com */
186310802Srene.dejong@arm.com
186410802Srene.dejong@arm.com
186510802Srene.dejong@arm.com/**
186610802Srene.dejong@arm.com * Dma transaction function: write device. Note that the dma action is
186710802Srene.dejong@arm.com * from a device perspective, while this function is from an initiator
186810802Srene.dejong@arm.com * perspective
186910802Srene.dejong@arm.com */
187010802Srene.dejong@arm.com
187110802Srene.dejong@arm.comvoid
187210802Srene.dejong@arm.comUFSHostDevice::writeDevice(Event* additional_action, bool toDisk, Addr
187310802Srene.dejong@arm.com                           start, int size, uint8_t* destination, uint64_t
187410802Srene.dejong@arm.com                           SCSIDiskOffset, uint32_t lun_id)
187510802Srene.dejong@arm.com{
187610802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write transaction Start: 0x%8x; Size: %d\n",
187710802Srene.dejong@arm.com            start, size);
187810802Srene.dejong@arm.com
187910802Srene.dejong@arm.com    /**check whether transfer is all the way to the flash*/
188010802Srene.dejong@arm.com    if (toDisk) {
188110802Srene.dejong@arm.com        ++writePendingNum;
188210802Srene.dejong@arm.com
188310802Srene.dejong@arm.com        while(!writeDoneEvent.empty() && (writeDoneEvent.front().when()
188410802Srene.dejong@arm.com                                          < curTick()))
188510802Srene.dejong@arm.com            writeDoneEvent.pop_front();
188610802Srene.dejong@arm.com
188710802Srene.dejong@arm.com        writeDoneEvent.push_back(this);
188810802Srene.dejong@arm.com        assert(!writeDoneEvent.back().scheduled());
188910802Srene.dejong@arm.com
189010802Srene.dejong@arm.com        /**destination is an offset here since we are writing to a disk*/
189110802Srene.dejong@arm.com        struct transferInfo new_transfer;
189210802Srene.dejong@arm.com        new_transfer.offset = SCSIDiskOffset;
189310802Srene.dejong@arm.com        new_transfer.size = size;
189410802Srene.dejong@arm.com        new_transfer.lunID = lun_id;
189510802Srene.dejong@arm.com        new_transfer.filePointer = 0;
189610802Srene.dejong@arm.com        SSDWriteinfo.push_back(new_transfer);
189710802Srene.dejong@arm.com
189810802Srene.dejong@arm.com        /**allocate appropriate buffer*/
189910802Srene.dejong@arm.com        SSDWriteinfo.back().buffer.resize(size);
190010802Srene.dejong@arm.com
190110802Srene.dejong@arm.com        /**transaction*/
190210802Srene.dejong@arm.com        dmaPort.dmaAction(MemCmd::ReadReq, start, size,
190310802Srene.dejong@arm.com                          &writeDoneEvent.back(),
190410802Srene.dejong@arm.com                          &SSDWriteinfo.back().buffer[0], 0);
190510802Srene.dejong@arm.com        //yes, a readreq at a write device function is correct.
190610802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write to disk scheduled\n");
190710802Srene.dejong@arm.com
190810802Srene.dejong@arm.com    } else {
190910802Srene.dejong@arm.com        assert(!additional_action->scheduled());
191010802Srene.dejong@arm.com        dmaPort.dmaAction(MemCmd::ReadReq, start, size,
191110802Srene.dejong@arm.com                          additional_action, destination, 0);
191210802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write scheduled\n");
191310802Srene.dejong@arm.com    }
191410802Srene.dejong@arm.com}
191510802Srene.dejong@arm.com
191610802Srene.dejong@arm.com/**
191710802Srene.dejong@arm.com * Manage write transfer. Manages correct transfer flow and makes sure that
191810802Srene.dejong@arm.com * the queues are filled on time
191910802Srene.dejong@arm.com */
192010802Srene.dejong@arm.com
192110802Srene.dejong@arm.comvoid
192210802Srene.dejong@arm.comUFSHostDevice::manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t
192310802Srene.dejong@arm.com                                   sg_table_length, struct UFSHCDSGEntry*
192410802Srene.dejong@arm.com                                   sglist)
192510802Srene.dejong@arm.com{
192610802Srene.dejong@arm.com    struct writeToDiskBurst next_packet;
192710802Srene.dejong@arm.com
192810802Srene.dejong@arm.com    next_packet.SCSIDiskOffset = offset;
192910802Srene.dejong@arm.com
193010802Srene.dejong@arm.com    UFSDevice[LUN]->setTotalWrite(sg_table_length);
193110802Srene.dejong@arm.com
193210802Srene.dejong@arm.com    /**
193310802Srene.dejong@arm.com     * Break-up the transactions into actions defined by the scatter gather
193410802Srene.dejong@arm.com     * list.
193510802Srene.dejong@arm.com     */
193610802Srene.dejong@arm.com    for (uint32_t count = 0; count < sg_table_length; count++) {
193710802Srene.dejong@arm.com        next_packet.start = sglist[count].upperAddr;
193810802Srene.dejong@arm.com        next_packet.start = (next_packet.start << 32) |
193910802Srene.dejong@arm.com            (sglist[count].baseAddr & 0xFFFFFFFF);
194010802Srene.dejong@arm.com        next_packet.LUN = LUN;
194110802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write data DMA start: 0x%8x\n",
194210802Srene.dejong@arm.com                next_packet.start);
194310802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write data DMA size: 0x%8x\n",
194410802Srene.dejong@arm.com                (sglist[count].size + 1));
194510802Srene.dejong@arm.com        assert(sglist[count].size > 0);
194610802Srene.dejong@arm.com
194710802Srene.dejong@arm.com        if (count != 0)
194810802Srene.dejong@arm.com            next_packet.SCSIDiskOffset = next_packet.SCSIDiskOffset +
194910802Srene.dejong@arm.com                (sglist[count - 1].size + 1);
195010802Srene.dejong@arm.com
195110802Srene.dejong@arm.com        next_packet.size = sglist[count].size + 1;
195210802Srene.dejong@arm.com
195310802Srene.dejong@arm.com        /**If the queue is empty, the transaction should be initiated*/
195410802Srene.dejong@arm.com        if (dmaWriteInfo.empty())
195510802Srene.dejong@arm.com            writeDevice(NULL, true, next_packet.start, next_packet.size,
195610802Srene.dejong@arm.com                        NULL, next_packet.SCSIDiskOffset, next_packet.LUN);
195710802Srene.dejong@arm.com        else
195810802Srene.dejong@arm.com            DPRINTF(UFSHostDevice, "Write not initiated queue: %d\n",
195910802Srene.dejong@arm.com                    dmaWriteInfo.size());
196010802Srene.dejong@arm.com
196110802Srene.dejong@arm.com        dmaWriteInfo.push_back(next_packet);
196210802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write Location: 0x%8x\n",
196310802Srene.dejong@arm.com                next_packet.SCSIDiskOffset);
196410802Srene.dejong@arm.com
196510802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write transfer #: 0x%8x\n", count + 1);
196610802Srene.dejong@arm.com
196710802Srene.dejong@arm.com        /** stats **/
196810802Srene.dejong@arm.com        stats.totalWrittenSSD += (sglist[count].size + 1);
196910802Srene.dejong@arm.com    }
197010802Srene.dejong@arm.com
197110802Srene.dejong@arm.com    /**stats**/
197210802Srene.dejong@arm.com    ++stats.totalWriteUFSTransactions;
197310802Srene.dejong@arm.com}
197410802Srene.dejong@arm.com
197510802Srene.dejong@arm.com/**
197610802Srene.dejong@arm.com * Write done handling function. Is only initiated when the flash is directly
197710802Srene.dejong@arm.com * approached
197810802Srene.dejong@arm.com */
197910802Srene.dejong@arm.com
198010802Srene.dejong@arm.comvoid
198110802Srene.dejong@arm.comUFSHostDevice::writeDone()
198210802Srene.dejong@arm.com{
198310802Srene.dejong@arm.com    /**DMA is done, information no longer needed*/
198410802Srene.dejong@arm.com    assert(dmaWriteInfo.size() > 0);
198510802Srene.dejong@arm.com    dmaWriteInfo.pop_front();
198610802Srene.dejong@arm.com    assert(SSDWriteinfo.size() > 0);
198710802Srene.dejong@arm.com    uint32_t lun = SSDWriteinfo.front().lunID;
198810802Srene.dejong@arm.com
198910802Srene.dejong@arm.com    /**If there is nothing on the way, we need to start the events*/
199010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write done entered, queue: %d\n",
199110802Srene.dejong@arm.com            UFSDevice[lun]->SSDWriteDoneInfo.size());
199210802Srene.dejong@arm.com    /**Write the disk*/
199310802Srene.dejong@arm.com    UFSDevice[lun]->writeFlash(&SSDWriteinfo.front().buffer[0],
199410802Srene.dejong@arm.com                               SSDWriteinfo.front().offset,
199510802Srene.dejong@arm.com                               SSDWriteinfo.front().size);
199610802Srene.dejong@arm.com
199710802Srene.dejong@arm.com    /**
199810802Srene.dejong@arm.com     * Move to the second queue, enter the logic unit
199910802Srene.dejong@arm.com     * This is where the disk is approached and the flash transaction is
200010802Srene.dejong@arm.com     * handled SSDWriteDone will take care of the timing
200110802Srene.dejong@arm.com     */
200210802Srene.dejong@arm.com    UFSDevice[lun]->SSDWriteDoneInfo.push_back(SSDWriteinfo.front());
200310802Srene.dejong@arm.com    SSDWriteinfo.pop_front();
200410802Srene.dejong@arm.com
200510802Srene.dejong@arm.com    --writePendingNum;
200610802Srene.dejong@arm.com    /**so far, only the DMA part has been handled, lets do the disk delay*/
200710802Srene.dejong@arm.com    UFSDevice[lun]->SSDWriteStart();
200810802Srene.dejong@arm.com
200910802Srene.dejong@arm.com    /** stats **/
201010802Srene.dejong@arm.com    stats.currentWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
201110802Srene.dejong@arm.com    stats.averageWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
201210802Srene.dejong@arm.com    ++stats.totalWriteDiskTransactions;
201310802Srene.dejong@arm.com
201410802Srene.dejong@arm.com    /**initiate the next dma action (if any)*/
201510802Srene.dejong@arm.com    if (!dmaWriteInfo.empty())
201610802Srene.dejong@arm.com        writeDevice(NULL, true, dmaWriteInfo.front().start,
201710802Srene.dejong@arm.com                    dmaWriteInfo.front().size,  NULL,
201810802Srene.dejong@arm.com                    dmaWriteInfo.front().SCSIDiskOffset,
201910802Srene.dejong@arm.com                    dmaWriteInfo.front().LUN);
202010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write done end\n");
202110802Srene.dejong@arm.com}
202210802Srene.dejong@arm.com
202310802Srene.dejong@arm.com/**
202410802Srene.dejong@arm.com * SSD write start. Starts the write action in the timing model
202510802Srene.dejong@arm.com */
202610802Srene.dejong@arm.comvoid
202710802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDWriteStart()
202810802Srene.dejong@arm.com{
202910802Srene.dejong@arm.com    assert(SSDWriteDoneInfo.size() > 0);
203010802Srene.dejong@arm.com    flashDevice->writeMemory(
203110802Srene.dejong@arm.com        SSDWriteDoneInfo.front().offset,
203210802Srene.dejong@arm.com        SSDWriteDoneInfo.front().size, memWriteCallback);
203310802Srene.dejong@arm.com
203410802Srene.dejong@arm.com    SSDWriteDoneInfo.pop_front();
203510802Srene.dejong@arm.com
203610802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write is started; left in queue: %d\n",
203710802Srene.dejong@arm.com            SSDWriteDoneInfo.size());
203810802Srene.dejong@arm.com}
203910802Srene.dejong@arm.com
204010802Srene.dejong@arm.com
204110802Srene.dejong@arm.com/**
204210802Srene.dejong@arm.com * SSDisk write done
204310802Srene.dejong@arm.com */
204410802Srene.dejong@arm.com
204510802Srene.dejong@arm.comvoid
204610802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDWriteDone()
204710802Srene.dejong@arm.com{
204810802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Write disk, aiming for %d messages, %d so far\n",
204910802Srene.dejong@arm.com            totalWrite, amountOfWriteTransfers);
205010802Srene.dejong@arm.com
205110802Srene.dejong@arm.com    //we have done one extra transfer
205210802Srene.dejong@arm.com    ++amountOfWriteTransfers;
205310802Srene.dejong@arm.com
205410802Srene.dejong@arm.com    /**test whether call was correct*/
205510802Srene.dejong@arm.com    assert(totalWrite >= amountOfWriteTransfers && totalWrite != 0);
205610802Srene.dejong@arm.com
205710802Srene.dejong@arm.com    /**are we there yet? (did we do everything)*/
205810802Srene.dejong@arm.com    if (totalWrite == amountOfWriteTransfers) {
205910802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Write transactions finished\n");
206010802Srene.dejong@arm.com        totalWrite = 0;
206110802Srene.dejong@arm.com        amountOfWriteTransfers = 0;
206210802Srene.dejong@arm.com
206310802Srene.dejong@arm.com        //Callback UFS Host
206410802Srene.dejong@arm.com        setSignal();
206510802Srene.dejong@arm.com        signalDone->process();
206610802Srene.dejong@arm.com    }
206710802Srene.dejong@arm.com
206810802Srene.dejong@arm.com}
206910802Srene.dejong@arm.com
207010802Srene.dejong@arm.com/**
207110802Srene.dejong@arm.com * Dma transaction function: read device. Notice that the dma action is from
207210802Srene.dejong@arm.com * a device perspective, while this function is from an initiator perspective
207310802Srene.dejong@arm.com */
207410802Srene.dejong@arm.com
207510802Srene.dejong@arm.comvoid
207610802Srene.dejong@arm.comUFSHostDevice::readDevice(bool lastTransfer, Addr start, uint32_t size,
207710802Srene.dejong@arm.com                          uint8_t* destination, bool no_cache, Event*
207810802Srene.dejong@arm.com                          additional_action)
207910802Srene.dejong@arm.com{
208010802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n",
208110802Srene.dejong@arm.com            start, size, (reinterpret_cast<uint32_t *>(destination))[0]);
208210802Srene.dejong@arm.com
208310802Srene.dejong@arm.com    /** check wether interrupt is needed */
208410802Srene.dejong@arm.com    if (lastTransfer) {
208510802Srene.dejong@arm.com        ++readPendingNum;
208610802Srene.dejong@arm.com        readDoneEvent.push_back(this);
208710802Srene.dejong@arm.com        assert(!readDoneEvent.back().scheduled());
208810802Srene.dejong@arm.com        dmaPort.dmaAction(MemCmd::WriteReq, start, size,
208910802Srene.dejong@arm.com                          &readDoneEvent.back(), destination, 0);
209010802Srene.dejong@arm.com        //yes, a writereq at a read device function is correct.
209110802Srene.dejong@arm.com
209210802Srene.dejong@arm.com    } else {
209310802Srene.dejong@arm.com        if (additional_action != NULL)
209410802Srene.dejong@arm.com            assert(!additional_action->scheduled());
209510802Srene.dejong@arm.com
209610802Srene.dejong@arm.com        dmaPort.dmaAction(MemCmd::WriteReq, start, size,
209710802Srene.dejong@arm.com                          additional_action, destination, 0);
209810802Srene.dejong@arm.com
209910802Srene.dejong@arm.com    }
210010802Srene.dejong@arm.com
210110802Srene.dejong@arm.com}
210210802Srene.dejong@arm.com
210310802Srene.dejong@arm.com/**
210410802Srene.dejong@arm.com * Manage read transfer. Manages correct transfer flow and makes sure that
210510802Srene.dejong@arm.com * the queues are filled on time
210610802Srene.dejong@arm.com */
210710802Srene.dejong@arm.com
210810802Srene.dejong@arm.comvoid
210910802Srene.dejong@arm.comUFSHostDevice::manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t
211010802Srene.dejong@arm.com                                  offset, uint32_t sg_table_length,
211110802Srene.dejong@arm.com                                  struct UFSHCDSGEntry* sglist)
211210802Srene.dejong@arm.com{
211310802Srene.dejong@arm.com    uint32_t size_accum = 0;
211410802Srene.dejong@arm.com
211510802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Data READ size: %d\n", size);
211610802Srene.dejong@arm.com
211710802Srene.dejong@arm.com    /**
211810802Srene.dejong@arm.com     * Break-up the transactions into actions defined by the scatter gather
211910802Srene.dejong@arm.com     * list.
212010802Srene.dejong@arm.com     */
212110802Srene.dejong@arm.com    for (uint32_t count = 0; count < sg_table_length; count++) {
212210802Srene.dejong@arm.com        struct transferInfo new_transfer;
212310802Srene.dejong@arm.com        new_transfer.offset = sglist[count].upperAddr;
212410802Srene.dejong@arm.com        new_transfer.offset = (new_transfer.offset << 32) |
212510802Srene.dejong@arm.com            (sglist[count].baseAddr & 0xFFFFFFFF);
212610802Srene.dejong@arm.com        new_transfer.filePointer = offset + size_accum;
212710802Srene.dejong@arm.com        new_transfer.size = (sglist[count].size + 1);
212810802Srene.dejong@arm.com        new_transfer.lunID = LUN;
212910802Srene.dejong@arm.com
213010802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Data READ start: 0x%8x; size: %d\n",
213110802Srene.dejong@arm.com                new_transfer.offset, new_transfer.size);
213210802Srene.dejong@arm.com
213310802Srene.dejong@arm.com        UFSDevice[LUN]->SSDReadInfo.push_back(new_transfer);
213410802Srene.dejong@arm.com        UFSDevice[LUN]->SSDReadInfo.back().buffer.resize(sglist[count].size
213510802Srene.dejong@arm.com                                                         + 1);
213610802Srene.dejong@arm.com
213710802Srene.dejong@arm.com        /**
213810802Srene.dejong@arm.com         * The disk image is read here; but the action is simultated later
213910802Srene.dejong@arm.com         * You can see this as the preparation stage, whereas later is the
214010802Srene.dejong@arm.com         * simulation phase.
214110802Srene.dejong@arm.com         */
214210802Srene.dejong@arm.com        UFSDevice[LUN]->readFlash(&UFSDevice[LUN]->
214310802Srene.dejong@arm.com                                  SSDReadInfo.back().buffer[0],
214410802Srene.dejong@arm.com                                  offset + size_accum,
214510802Srene.dejong@arm.com                                  sglist[count].size + 1);
214610802Srene.dejong@arm.com
214710802Srene.dejong@arm.com        size_accum += (sglist[count].size + 1);
214810802Srene.dejong@arm.com
214910802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "Transfer %d; Remaining: 0x%8x, Accumulated:"
215010802Srene.dejong@arm.com                " 0x%8x\n", (count + 1), (size-size_accum), size_accum);
215110802Srene.dejong@arm.com
215210802Srene.dejong@arm.com        /** stats **/
215310802Srene.dejong@arm.com        stats.totalReadSSD += (sglist[count].size + 1);
215410802Srene.dejong@arm.com        stats.currentReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
215510802Srene.dejong@arm.com        stats.averageReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
215610802Srene.dejong@arm.com    }
215710802Srene.dejong@arm.com
215810802Srene.dejong@arm.com    UFSDevice[LUN]->SSDReadStart(sg_table_length);
215910802Srene.dejong@arm.com
216010802Srene.dejong@arm.com    /** stats **/
216110802Srene.dejong@arm.com    ++stats.totalReadUFSTransactions;
216210802Srene.dejong@arm.com
216310802Srene.dejong@arm.com}
216410802Srene.dejong@arm.com
216510802Srene.dejong@arm.com
216610802Srene.dejong@arm.com
216710802Srene.dejong@arm.com/**
216810802Srene.dejong@arm.com * SSDisk start read; this function was created to keep the interfaces
216910802Srene.dejong@arm.com * between the layers simpler. Without this function UFSHost would need to
217010802Srene.dejong@arm.com * know about the flashdevice.
217110802Srene.dejong@arm.com */
217210802Srene.dejong@arm.com
217310802Srene.dejong@arm.comvoid
217410802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDReadStart(uint32_t total_read)
217510802Srene.dejong@arm.com{
217610802Srene.dejong@arm.com    totalRead = total_read;
217710802Srene.dejong@arm.com    for (uint32_t number_handled = 0; number_handled < SSDReadInfo.size();
217810802Srene.dejong@arm.com         number_handled++) {
217910802Srene.dejong@arm.com        /**
218010802Srene.dejong@arm.com         * Load all the read request to the Memory device.
218110802Srene.dejong@arm.com         * It will call back when done.
218210802Srene.dejong@arm.com         */
218310802Srene.dejong@arm.com        flashDevice->readMemory(SSDReadInfo.front().filePointer,
218410802Srene.dejong@arm.com                                SSDReadInfo.front().size, memReadCallback);
218510802Srene.dejong@arm.com    }
218610802Srene.dejong@arm.com
218710802Srene.dejong@arm.com}
218810802Srene.dejong@arm.com
218910802Srene.dejong@arm.com
219010802Srene.dejong@arm.com/**
219110802Srene.dejong@arm.com * SSDisk read done
219210802Srene.dejong@arm.com */
219310802Srene.dejong@arm.com
219410802Srene.dejong@arm.comvoid
219510802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDReadDone()
219610802Srene.dejong@arm.com{
219710802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "SSD read done at lun %d, Aiming for %d messages,"
219810802Srene.dejong@arm.com            " %d so far\n", lunID, totalRead, amountOfReadTransfers);
219910802Srene.dejong@arm.com
220010802Srene.dejong@arm.com    if (totalRead == amountOfReadTransfers) {
220110802Srene.dejong@arm.com        totalRead = 0;
220210802Srene.dejong@arm.com        amountOfReadTransfers = 0;
220310802Srene.dejong@arm.com
220410802Srene.dejong@arm.com        /**Callback: transferdone*/
220510802Srene.dejong@arm.com        setSignal();
220610802Srene.dejong@arm.com        signalDone->process();
220710802Srene.dejong@arm.com    }
220810802Srene.dejong@arm.com
220910802Srene.dejong@arm.com}
221010802Srene.dejong@arm.com
221110802Srene.dejong@arm.com/**
221210802Srene.dejong@arm.com * Read callback, on the way from the disk to the DMA. Called by the flash
221310802Srene.dejong@arm.com * layer. Intermediate step to the host layer
221410802Srene.dejong@arm.com */
221510802Srene.dejong@arm.comvoid
221610802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::readCallback()
221710802Srene.dejong@arm.com{
221810802Srene.dejong@arm.com    ++amountOfReadTransfers;
221910802Srene.dejong@arm.com
222010802Srene.dejong@arm.com    /**Callback; make sure data is transfered upstream:
222110802Srene.dejong@arm.com     * UFSHostDevice::readCallback
222210802Srene.dejong@arm.com     */
222310802Srene.dejong@arm.com    setReadSignal();
222410802Srene.dejong@arm.com    deviceReadCallback->process();
222510802Srene.dejong@arm.com
222610802Srene.dejong@arm.com    //Are we done yet?
222710802Srene.dejong@arm.com    SSDReadDone();
222810802Srene.dejong@arm.com}
222910802Srene.dejong@arm.com
223010802Srene.dejong@arm.com/**
223110802Srene.dejong@arm.com * Read callback, on the way from the disk to the DMA. Called by the UFSSCSI
223210802Srene.dejong@arm.com * layer.
223310802Srene.dejong@arm.com */
223410802Srene.dejong@arm.com
223510802Srene.dejong@arm.comvoid
223610802Srene.dejong@arm.comUFSHostDevice::readCallback()
223710802Srene.dejong@arm.com{
223810802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Read Callback\n");
223910802Srene.dejong@arm.com    uint8_t this_lun = 0;
224010802Srene.dejong@arm.com
224110802Srene.dejong@arm.com    //while we haven't found the right lun, keep searching
224210802Srene.dejong@arm.com    while((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedRead())
224310802Srene.dejong@arm.com        ++this_lun;
224410802Srene.dejong@arm.com
224510802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Found LUN %d messages pending for clean: %d\n",
224610802Srene.dejong@arm.com            this_lun, SSDReadPending.size());
224710802Srene.dejong@arm.com
224810802Srene.dejong@arm.com    if (this_lun < lunAvail) {
224910802Srene.dejong@arm.com        //Clear signal.
225010802Srene.dejong@arm.com        UFSDevice[this_lun]->clearReadSignal();
225110802Srene.dejong@arm.com        SSDReadPending.push_back(UFSDevice[this_lun]->SSDReadInfo.front());
225210802Srene.dejong@arm.com        UFSDevice[this_lun]->SSDReadInfo.pop_front();
225310802Srene.dejong@arm.com        readGarbageEventQueue.push_back(this);
225410802Srene.dejong@arm.com
225510802Srene.dejong@arm.com        //make sure the queue is popped a the end of the dma transaction
225610802Srene.dejong@arm.com        readDevice(false, SSDReadPending.front().offset,
225710802Srene.dejong@arm.com                   SSDReadPending.front().size,
225810802Srene.dejong@arm.com                   &SSDReadPending.front().buffer[0], false,
225910802Srene.dejong@arm.com                   &readGarbageEventQueue.back());
226010802Srene.dejong@arm.com
226110802Srene.dejong@arm.com        /**stats*/
226210802Srene.dejong@arm.com        ++stats.totalReadDiskTransactions;
226310802Srene.dejong@arm.com    }
226410802Srene.dejong@arm.com    else
226510802Srene.dejong@arm.com        panic("no read finished in tick %d\n", curTick());
226610802Srene.dejong@arm.com}
226710802Srene.dejong@arm.com
226810802Srene.dejong@arm.com/**
226910802Srene.dejong@arm.com * After a disk read DMA transfer, the structure needs to be freed. This is
227010802Srene.dejong@arm.com * done in this function.
227110802Srene.dejong@arm.com */
227210802Srene.dejong@arm.comvoid
227310802Srene.dejong@arm.comUFSHostDevice::readGarbage()
227410802Srene.dejong@arm.com{
227510802Srene.dejong@arm.com    DPRINTF(UFSHostDevice, "Clean read data, %d\n", SSDReadPending.size());
227610802Srene.dejong@arm.com    SSDReadPending.pop_front();
227710802Srene.dejong@arm.com    readGarbageEventQueue.pop_front();
227810802Srene.dejong@arm.com}
227910802Srene.dejong@arm.com
228010802Srene.dejong@arm.com/**
228110802Srene.dejong@arm.com * Serialize; needed to make checkpoints
228210802Srene.dejong@arm.com */
228310802Srene.dejong@arm.com
228410802Srene.dejong@arm.comvoid
228510905Sandreas.sandberg@arm.comUFSHostDevice::serialize(CheckpointOut &cp) const
228610802Srene.dejong@arm.com{
228710905Sandreas.sandberg@arm.com    DmaDevice::serialize(cp);
228810905Sandreas.sandberg@arm.com
228910905Sandreas.sandberg@arm.com    const uint8_t* temp_HCI_mem = reinterpret_cast<const uint8_t*>(&UFSHCIMem);
229010802Srene.dejong@arm.com    SERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
229110802Srene.dejong@arm.com
229210802Srene.dejong@arm.com    uint32_t lun_avail = lunAvail;
229310802Srene.dejong@arm.com    SERIALIZE_SCALAR(lun_avail);
229410802Srene.dejong@arm.com}
229510802Srene.dejong@arm.com
229610802Srene.dejong@arm.com
229710802Srene.dejong@arm.com/**
229810802Srene.dejong@arm.com * Unserialize; needed to restore from checkpoints
229910802Srene.dejong@arm.com */
230010802Srene.dejong@arm.com
230110802Srene.dejong@arm.comvoid
230210905Sandreas.sandberg@arm.comUFSHostDevice::unserialize(CheckpointIn &cp)
230310802Srene.dejong@arm.com{
230410905Sandreas.sandberg@arm.com    DmaDevice::unserialize(cp);
230510802Srene.dejong@arm.com    uint8_t* temp_HCI_mem = reinterpret_cast<uint8_t*>(&UFSHCIMem);
230610802Srene.dejong@arm.com    UNSERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
230710802Srene.dejong@arm.com
230810802Srene.dejong@arm.com    uint32_t lun_avail;
230910802Srene.dejong@arm.com    UNSERIALIZE_SCALAR(lun_avail);
231010802Srene.dejong@arm.com    assert(lunAvail == lun_avail);
231110802Srene.dejong@arm.com}
231210802Srene.dejong@arm.com
231310802Srene.dejong@arm.com
231410802Srene.dejong@arm.com/**
231510802Srene.dejong@arm.com * Drain; needed to enable checkpoints
231610802Srene.dejong@arm.com */
231710802Srene.dejong@arm.com
231810913Sandreas.sandberg@arm.comDrainState
231910913Sandreas.sandberg@arm.comUFSHostDevice::drain()
232010802Srene.dejong@arm.com{
232110802Srene.dejong@arm.com    if (UFSHCIMem.TRUTRLDBR) {
232210802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "UFSDevice is draining...\n");
232310913Sandreas.sandberg@arm.com        return DrainState::Draining;
232410802Srene.dejong@arm.com    } else {
232510802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "UFSDevice drained\n");
232610913Sandreas.sandberg@arm.com        return DrainState::Drained;
232710802Srene.dejong@arm.com    }
232810802Srene.dejong@arm.com}
232910802Srene.dejong@arm.com
233010802Srene.dejong@arm.com/**
233110802Srene.dejong@arm.com * Checkdrain; needed to enable checkpoints
233210802Srene.dejong@arm.com */
233310802Srene.dejong@arm.com
233410802Srene.dejong@arm.comvoid
233510802Srene.dejong@arm.comUFSHostDevice::checkDrain()
233610802Srene.dejong@arm.com{
233710913Sandreas.sandberg@arm.com    if (drainState() != DrainState::Draining)
233810802Srene.dejong@arm.com        return;
233910802Srene.dejong@arm.com
234010802Srene.dejong@arm.com    if (UFSHCIMem.TRUTRLDBR) {
234110802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "UFSDevice is still draining; with %d active"
234210802Srene.dejong@arm.com            " doorbells\n", activeDoorbells);
234310802Srene.dejong@arm.com    } else {
234410802Srene.dejong@arm.com        DPRINTF(UFSHostDevice, "UFSDevice is done draining\n");
234510913Sandreas.sandberg@arm.com        signalDrainDone();
234610802Srene.dejong@arm.com    }
234710802Srene.dejong@arm.com}
2348