ufs_device.cc revision 11179
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 182511179Ssascha.bischoff@ARM.com checkDrain(); 182611179Ssascha.bischoff@ARM.com 182710802Srene.dejong@arm.com /**step6 raise interrupt*/ 182810802Srene.dejong@arm.com gic->sendInt(intNum); 182910802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Send interrupt @ transaction: 0x%8x!\n", 183010802Srene.dejong@arm.com countInt); 183110802Srene.dejong@arm.com} 183210802Srene.dejong@arm.com 183310802Srene.dejong@arm.com/** 183410802Srene.dejong@arm.com * Clear interrupt 183510802Srene.dejong@arm.com */ 183610802Srene.dejong@arm.com 183710802Srene.dejong@arm.comvoid 183810802Srene.dejong@arm.comUFSHostDevice::clearInterrupt() 183910802Srene.dejong@arm.com{ 184010802Srene.dejong@arm.com gic->clearInt(intNum); 184110802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Clear interrupt: 0x%8x!\n", countInt); 184210802Srene.dejong@arm.com 184311179Ssascha.bischoff@ARM.com checkDrain(); 184411179Ssascha.bischoff@ARM.com 184510802Srene.dejong@arm.com if (!(UFSHCIMem.TRUTRLDBR)) { 184610802Srene.dejong@arm.com idlePhaseStart = curTick(); 184710802Srene.dejong@arm.com } 184810802Srene.dejong@arm.com /**end of a transaction*/ 184910802Srene.dejong@arm.com} 185010802Srene.dejong@arm.com 185110802Srene.dejong@arm.com/** 185210802Srene.dejong@arm.com * Important to understand about the transfer flow: 185310802Srene.dejong@arm.com * We have basically three stages, The "system memory" stage, the "device 185410802Srene.dejong@arm.com * buffer" stage and the "disk" stage. In this model we assume an infinite 185510802Srene.dejong@arm.com * buffer, or a buffer that is big enough to store all the data in the 185610802Srene.dejong@arm.com * biggest transaction. Between the three stages are two queues. Those queues 185710802Srene.dejong@arm.com * store the messages to simulate their transaction from one stage to the 185810802Srene.dejong@arm.com * next. The manage{Action} function fills up one of the queues and triggers 185910802Srene.dejong@arm.com * the first event, which causes a chain reaction of events executed once 186010802Srene.dejong@arm.com * they pass through their queues. For a write action the stages are ordered 186110802Srene.dejong@arm.com * "system memory", "device buffer" and "disk", whereas the read transfers 186210802Srene.dejong@arm.com * happen "disk", "device buffer" and "system memory". The dma action in the 186310802Srene.dejong@arm.com * dma device is written from a bus perspective whereas this model is written 186410802Srene.dejong@arm.com * from a device perspective. To avoid confusion, the translation between the 186510802Srene.dejong@arm.com * two has been made in the writeDevice and readDevice funtions. 186610802Srene.dejong@arm.com */ 186710802Srene.dejong@arm.com 186810802Srene.dejong@arm.com 186910802Srene.dejong@arm.com/** 187010802Srene.dejong@arm.com * Dma transaction function: write device. Note that the dma action is 187110802Srene.dejong@arm.com * from a device perspective, while this function is from an initiator 187210802Srene.dejong@arm.com * perspective 187310802Srene.dejong@arm.com */ 187410802Srene.dejong@arm.com 187510802Srene.dejong@arm.comvoid 187610802Srene.dejong@arm.comUFSHostDevice::writeDevice(Event* additional_action, bool toDisk, Addr 187710802Srene.dejong@arm.com start, int size, uint8_t* destination, uint64_t 187810802Srene.dejong@arm.com SCSIDiskOffset, uint32_t lun_id) 187910802Srene.dejong@arm.com{ 188010802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write transaction Start: 0x%8x; Size: %d\n", 188110802Srene.dejong@arm.com start, size); 188210802Srene.dejong@arm.com 188310802Srene.dejong@arm.com /**check whether transfer is all the way to the flash*/ 188410802Srene.dejong@arm.com if (toDisk) { 188510802Srene.dejong@arm.com ++writePendingNum; 188610802Srene.dejong@arm.com 188710802Srene.dejong@arm.com while(!writeDoneEvent.empty() && (writeDoneEvent.front().when() 188810802Srene.dejong@arm.com < curTick())) 188910802Srene.dejong@arm.com writeDoneEvent.pop_front(); 189010802Srene.dejong@arm.com 189110802Srene.dejong@arm.com writeDoneEvent.push_back(this); 189210802Srene.dejong@arm.com assert(!writeDoneEvent.back().scheduled()); 189310802Srene.dejong@arm.com 189410802Srene.dejong@arm.com /**destination is an offset here since we are writing to a disk*/ 189510802Srene.dejong@arm.com struct transferInfo new_transfer; 189610802Srene.dejong@arm.com new_transfer.offset = SCSIDiskOffset; 189710802Srene.dejong@arm.com new_transfer.size = size; 189810802Srene.dejong@arm.com new_transfer.lunID = lun_id; 189910802Srene.dejong@arm.com new_transfer.filePointer = 0; 190010802Srene.dejong@arm.com SSDWriteinfo.push_back(new_transfer); 190110802Srene.dejong@arm.com 190210802Srene.dejong@arm.com /**allocate appropriate buffer*/ 190310802Srene.dejong@arm.com SSDWriteinfo.back().buffer.resize(size); 190410802Srene.dejong@arm.com 190510802Srene.dejong@arm.com /**transaction*/ 190610802Srene.dejong@arm.com dmaPort.dmaAction(MemCmd::ReadReq, start, size, 190710802Srene.dejong@arm.com &writeDoneEvent.back(), 190810802Srene.dejong@arm.com &SSDWriteinfo.back().buffer[0], 0); 190910802Srene.dejong@arm.com //yes, a readreq at a write device function is correct. 191010802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write to disk scheduled\n"); 191110802Srene.dejong@arm.com 191210802Srene.dejong@arm.com } else { 191310802Srene.dejong@arm.com assert(!additional_action->scheduled()); 191410802Srene.dejong@arm.com dmaPort.dmaAction(MemCmd::ReadReq, start, size, 191510802Srene.dejong@arm.com additional_action, destination, 0); 191610802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write scheduled\n"); 191710802Srene.dejong@arm.com } 191810802Srene.dejong@arm.com} 191910802Srene.dejong@arm.com 192010802Srene.dejong@arm.com/** 192110802Srene.dejong@arm.com * Manage write transfer. Manages correct transfer flow and makes sure that 192210802Srene.dejong@arm.com * the queues are filled on time 192310802Srene.dejong@arm.com */ 192410802Srene.dejong@arm.com 192510802Srene.dejong@arm.comvoid 192610802Srene.dejong@arm.comUFSHostDevice::manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t 192710802Srene.dejong@arm.com sg_table_length, struct UFSHCDSGEntry* 192810802Srene.dejong@arm.com sglist) 192910802Srene.dejong@arm.com{ 193010802Srene.dejong@arm.com struct writeToDiskBurst next_packet; 193110802Srene.dejong@arm.com 193210802Srene.dejong@arm.com next_packet.SCSIDiskOffset = offset; 193310802Srene.dejong@arm.com 193410802Srene.dejong@arm.com UFSDevice[LUN]->setTotalWrite(sg_table_length); 193510802Srene.dejong@arm.com 193610802Srene.dejong@arm.com /** 193710802Srene.dejong@arm.com * Break-up the transactions into actions defined by the scatter gather 193810802Srene.dejong@arm.com * list. 193910802Srene.dejong@arm.com */ 194010802Srene.dejong@arm.com for (uint32_t count = 0; count < sg_table_length; count++) { 194110802Srene.dejong@arm.com next_packet.start = sglist[count].upperAddr; 194210802Srene.dejong@arm.com next_packet.start = (next_packet.start << 32) | 194310802Srene.dejong@arm.com (sglist[count].baseAddr & 0xFFFFFFFF); 194410802Srene.dejong@arm.com next_packet.LUN = LUN; 194510802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write data DMA start: 0x%8x\n", 194610802Srene.dejong@arm.com next_packet.start); 194710802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write data DMA size: 0x%8x\n", 194810802Srene.dejong@arm.com (sglist[count].size + 1)); 194910802Srene.dejong@arm.com assert(sglist[count].size > 0); 195010802Srene.dejong@arm.com 195110802Srene.dejong@arm.com if (count != 0) 195210802Srene.dejong@arm.com next_packet.SCSIDiskOffset = next_packet.SCSIDiskOffset + 195310802Srene.dejong@arm.com (sglist[count - 1].size + 1); 195410802Srene.dejong@arm.com 195510802Srene.dejong@arm.com next_packet.size = sglist[count].size + 1; 195610802Srene.dejong@arm.com 195710802Srene.dejong@arm.com /**If the queue is empty, the transaction should be initiated*/ 195810802Srene.dejong@arm.com if (dmaWriteInfo.empty()) 195910802Srene.dejong@arm.com writeDevice(NULL, true, next_packet.start, next_packet.size, 196010802Srene.dejong@arm.com NULL, next_packet.SCSIDiskOffset, next_packet.LUN); 196110802Srene.dejong@arm.com else 196210802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write not initiated queue: %d\n", 196310802Srene.dejong@arm.com dmaWriteInfo.size()); 196410802Srene.dejong@arm.com 196510802Srene.dejong@arm.com dmaWriteInfo.push_back(next_packet); 196610802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write Location: 0x%8x\n", 196710802Srene.dejong@arm.com next_packet.SCSIDiskOffset); 196810802Srene.dejong@arm.com 196910802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write transfer #: 0x%8x\n", count + 1); 197010802Srene.dejong@arm.com 197110802Srene.dejong@arm.com /** stats **/ 197210802Srene.dejong@arm.com stats.totalWrittenSSD += (sglist[count].size + 1); 197310802Srene.dejong@arm.com } 197410802Srene.dejong@arm.com 197510802Srene.dejong@arm.com /**stats**/ 197610802Srene.dejong@arm.com ++stats.totalWriteUFSTransactions; 197710802Srene.dejong@arm.com} 197810802Srene.dejong@arm.com 197910802Srene.dejong@arm.com/** 198010802Srene.dejong@arm.com * Write done handling function. Is only initiated when the flash is directly 198110802Srene.dejong@arm.com * approached 198210802Srene.dejong@arm.com */ 198310802Srene.dejong@arm.com 198410802Srene.dejong@arm.comvoid 198510802Srene.dejong@arm.comUFSHostDevice::writeDone() 198610802Srene.dejong@arm.com{ 198710802Srene.dejong@arm.com /**DMA is done, information no longer needed*/ 198810802Srene.dejong@arm.com assert(dmaWriteInfo.size() > 0); 198910802Srene.dejong@arm.com dmaWriteInfo.pop_front(); 199010802Srene.dejong@arm.com assert(SSDWriteinfo.size() > 0); 199110802Srene.dejong@arm.com uint32_t lun = SSDWriteinfo.front().lunID; 199210802Srene.dejong@arm.com 199310802Srene.dejong@arm.com /**If there is nothing on the way, we need to start the events*/ 199410802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write done entered, queue: %d\n", 199510802Srene.dejong@arm.com UFSDevice[lun]->SSDWriteDoneInfo.size()); 199610802Srene.dejong@arm.com /**Write the disk*/ 199710802Srene.dejong@arm.com UFSDevice[lun]->writeFlash(&SSDWriteinfo.front().buffer[0], 199810802Srene.dejong@arm.com SSDWriteinfo.front().offset, 199910802Srene.dejong@arm.com SSDWriteinfo.front().size); 200010802Srene.dejong@arm.com 200110802Srene.dejong@arm.com /** 200210802Srene.dejong@arm.com * Move to the second queue, enter the logic unit 200310802Srene.dejong@arm.com * This is where the disk is approached and the flash transaction is 200410802Srene.dejong@arm.com * handled SSDWriteDone will take care of the timing 200510802Srene.dejong@arm.com */ 200610802Srene.dejong@arm.com UFSDevice[lun]->SSDWriteDoneInfo.push_back(SSDWriteinfo.front()); 200710802Srene.dejong@arm.com SSDWriteinfo.pop_front(); 200810802Srene.dejong@arm.com 200910802Srene.dejong@arm.com --writePendingNum; 201010802Srene.dejong@arm.com /**so far, only the DMA part has been handled, lets do the disk delay*/ 201110802Srene.dejong@arm.com UFSDevice[lun]->SSDWriteStart(); 201210802Srene.dejong@arm.com 201310802Srene.dejong@arm.com /** stats **/ 201410802Srene.dejong@arm.com stats.currentWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size(); 201510802Srene.dejong@arm.com stats.averageWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size(); 201610802Srene.dejong@arm.com ++stats.totalWriteDiskTransactions; 201710802Srene.dejong@arm.com 201810802Srene.dejong@arm.com /**initiate the next dma action (if any)*/ 201910802Srene.dejong@arm.com if (!dmaWriteInfo.empty()) 202010802Srene.dejong@arm.com writeDevice(NULL, true, dmaWriteInfo.front().start, 202110802Srene.dejong@arm.com dmaWriteInfo.front().size, NULL, 202210802Srene.dejong@arm.com dmaWriteInfo.front().SCSIDiskOffset, 202310802Srene.dejong@arm.com dmaWriteInfo.front().LUN); 202410802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write done end\n"); 202510802Srene.dejong@arm.com} 202610802Srene.dejong@arm.com 202710802Srene.dejong@arm.com/** 202810802Srene.dejong@arm.com * SSD write start. Starts the write action in the timing model 202910802Srene.dejong@arm.com */ 203010802Srene.dejong@arm.comvoid 203110802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDWriteStart() 203210802Srene.dejong@arm.com{ 203310802Srene.dejong@arm.com assert(SSDWriteDoneInfo.size() > 0); 203410802Srene.dejong@arm.com flashDevice->writeMemory( 203510802Srene.dejong@arm.com SSDWriteDoneInfo.front().offset, 203610802Srene.dejong@arm.com SSDWriteDoneInfo.front().size, memWriteCallback); 203710802Srene.dejong@arm.com 203810802Srene.dejong@arm.com SSDWriteDoneInfo.pop_front(); 203910802Srene.dejong@arm.com 204010802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write is started; left in queue: %d\n", 204110802Srene.dejong@arm.com SSDWriteDoneInfo.size()); 204210802Srene.dejong@arm.com} 204310802Srene.dejong@arm.com 204410802Srene.dejong@arm.com 204510802Srene.dejong@arm.com/** 204610802Srene.dejong@arm.com * SSDisk write done 204710802Srene.dejong@arm.com */ 204810802Srene.dejong@arm.com 204910802Srene.dejong@arm.comvoid 205010802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDWriteDone() 205110802Srene.dejong@arm.com{ 205210802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write disk, aiming for %d messages, %d so far\n", 205310802Srene.dejong@arm.com totalWrite, amountOfWriteTransfers); 205410802Srene.dejong@arm.com 205510802Srene.dejong@arm.com //we have done one extra transfer 205610802Srene.dejong@arm.com ++amountOfWriteTransfers; 205710802Srene.dejong@arm.com 205810802Srene.dejong@arm.com /**test whether call was correct*/ 205910802Srene.dejong@arm.com assert(totalWrite >= amountOfWriteTransfers && totalWrite != 0); 206010802Srene.dejong@arm.com 206110802Srene.dejong@arm.com /**are we there yet? (did we do everything)*/ 206210802Srene.dejong@arm.com if (totalWrite == amountOfWriteTransfers) { 206310802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Write transactions finished\n"); 206410802Srene.dejong@arm.com totalWrite = 0; 206510802Srene.dejong@arm.com amountOfWriteTransfers = 0; 206610802Srene.dejong@arm.com 206710802Srene.dejong@arm.com //Callback UFS Host 206810802Srene.dejong@arm.com setSignal(); 206910802Srene.dejong@arm.com signalDone->process(); 207010802Srene.dejong@arm.com } 207110802Srene.dejong@arm.com 207210802Srene.dejong@arm.com} 207310802Srene.dejong@arm.com 207410802Srene.dejong@arm.com/** 207510802Srene.dejong@arm.com * Dma transaction function: read device. Notice that the dma action is from 207610802Srene.dejong@arm.com * a device perspective, while this function is from an initiator perspective 207710802Srene.dejong@arm.com */ 207810802Srene.dejong@arm.com 207910802Srene.dejong@arm.comvoid 208010802Srene.dejong@arm.comUFSHostDevice::readDevice(bool lastTransfer, Addr start, uint32_t size, 208110802Srene.dejong@arm.com uint8_t* destination, bool no_cache, Event* 208210802Srene.dejong@arm.com additional_action) 208310802Srene.dejong@arm.com{ 208410802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n", 208510802Srene.dejong@arm.com start, size, (reinterpret_cast<uint32_t *>(destination))[0]); 208610802Srene.dejong@arm.com 208710802Srene.dejong@arm.com /** check wether interrupt is needed */ 208810802Srene.dejong@arm.com if (lastTransfer) { 208910802Srene.dejong@arm.com ++readPendingNum; 209010802Srene.dejong@arm.com readDoneEvent.push_back(this); 209110802Srene.dejong@arm.com assert(!readDoneEvent.back().scheduled()); 209210802Srene.dejong@arm.com dmaPort.dmaAction(MemCmd::WriteReq, start, size, 209310802Srene.dejong@arm.com &readDoneEvent.back(), destination, 0); 209410802Srene.dejong@arm.com //yes, a writereq at a read device function is correct. 209510802Srene.dejong@arm.com 209610802Srene.dejong@arm.com } else { 209710802Srene.dejong@arm.com if (additional_action != NULL) 209810802Srene.dejong@arm.com assert(!additional_action->scheduled()); 209910802Srene.dejong@arm.com 210010802Srene.dejong@arm.com dmaPort.dmaAction(MemCmd::WriteReq, start, size, 210110802Srene.dejong@arm.com additional_action, destination, 0); 210210802Srene.dejong@arm.com 210310802Srene.dejong@arm.com } 210410802Srene.dejong@arm.com 210510802Srene.dejong@arm.com} 210610802Srene.dejong@arm.com 210710802Srene.dejong@arm.com/** 210810802Srene.dejong@arm.com * Manage read transfer. Manages correct transfer flow and makes sure that 210910802Srene.dejong@arm.com * the queues are filled on time 211010802Srene.dejong@arm.com */ 211110802Srene.dejong@arm.com 211210802Srene.dejong@arm.comvoid 211310802Srene.dejong@arm.comUFSHostDevice::manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t 211410802Srene.dejong@arm.com offset, uint32_t sg_table_length, 211510802Srene.dejong@arm.com struct UFSHCDSGEntry* sglist) 211610802Srene.dejong@arm.com{ 211710802Srene.dejong@arm.com uint32_t size_accum = 0; 211810802Srene.dejong@arm.com 211910802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Data READ size: %d\n", size); 212010802Srene.dejong@arm.com 212110802Srene.dejong@arm.com /** 212210802Srene.dejong@arm.com * Break-up the transactions into actions defined by the scatter gather 212310802Srene.dejong@arm.com * list. 212410802Srene.dejong@arm.com */ 212510802Srene.dejong@arm.com for (uint32_t count = 0; count < sg_table_length; count++) { 212610802Srene.dejong@arm.com struct transferInfo new_transfer; 212710802Srene.dejong@arm.com new_transfer.offset = sglist[count].upperAddr; 212810802Srene.dejong@arm.com new_transfer.offset = (new_transfer.offset << 32) | 212910802Srene.dejong@arm.com (sglist[count].baseAddr & 0xFFFFFFFF); 213010802Srene.dejong@arm.com new_transfer.filePointer = offset + size_accum; 213110802Srene.dejong@arm.com new_transfer.size = (sglist[count].size + 1); 213210802Srene.dejong@arm.com new_transfer.lunID = LUN; 213310802Srene.dejong@arm.com 213410802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Data READ start: 0x%8x; size: %d\n", 213510802Srene.dejong@arm.com new_transfer.offset, new_transfer.size); 213610802Srene.dejong@arm.com 213710802Srene.dejong@arm.com UFSDevice[LUN]->SSDReadInfo.push_back(new_transfer); 213810802Srene.dejong@arm.com UFSDevice[LUN]->SSDReadInfo.back().buffer.resize(sglist[count].size 213910802Srene.dejong@arm.com + 1); 214010802Srene.dejong@arm.com 214110802Srene.dejong@arm.com /** 214210802Srene.dejong@arm.com * The disk image is read here; but the action is simultated later 214310802Srene.dejong@arm.com * You can see this as the preparation stage, whereas later is the 214410802Srene.dejong@arm.com * simulation phase. 214510802Srene.dejong@arm.com */ 214610802Srene.dejong@arm.com UFSDevice[LUN]->readFlash(&UFSDevice[LUN]-> 214710802Srene.dejong@arm.com SSDReadInfo.back().buffer[0], 214810802Srene.dejong@arm.com offset + size_accum, 214910802Srene.dejong@arm.com sglist[count].size + 1); 215010802Srene.dejong@arm.com 215110802Srene.dejong@arm.com size_accum += (sglist[count].size + 1); 215210802Srene.dejong@arm.com 215310802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Transfer %d; Remaining: 0x%8x, Accumulated:" 215410802Srene.dejong@arm.com " 0x%8x\n", (count + 1), (size-size_accum), size_accum); 215510802Srene.dejong@arm.com 215610802Srene.dejong@arm.com /** stats **/ 215710802Srene.dejong@arm.com stats.totalReadSSD += (sglist[count].size + 1); 215810802Srene.dejong@arm.com stats.currentReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size(); 215910802Srene.dejong@arm.com stats.averageReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size(); 216010802Srene.dejong@arm.com } 216110802Srene.dejong@arm.com 216210802Srene.dejong@arm.com UFSDevice[LUN]->SSDReadStart(sg_table_length); 216310802Srene.dejong@arm.com 216410802Srene.dejong@arm.com /** stats **/ 216510802Srene.dejong@arm.com ++stats.totalReadUFSTransactions; 216610802Srene.dejong@arm.com 216710802Srene.dejong@arm.com} 216810802Srene.dejong@arm.com 216910802Srene.dejong@arm.com 217010802Srene.dejong@arm.com 217110802Srene.dejong@arm.com/** 217210802Srene.dejong@arm.com * SSDisk start read; this function was created to keep the interfaces 217310802Srene.dejong@arm.com * between the layers simpler. Without this function UFSHost would need to 217410802Srene.dejong@arm.com * know about the flashdevice. 217510802Srene.dejong@arm.com */ 217610802Srene.dejong@arm.com 217710802Srene.dejong@arm.comvoid 217810802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDReadStart(uint32_t total_read) 217910802Srene.dejong@arm.com{ 218010802Srene.dejong@arm.com totalRead = total_read; 218110802Srene.dejong@arm.com for (uint32_t number_handled = 0; number_handled < SSDReadInfo.size(); 218210802Srene.dejong@arm.com number_handled++) { 218310802Srene.dejong@arm.com /** 218410802Srene.dejong@arm.com * Load all the read request to the Memory device. 218510802Srene.dejong@arm.com * It will call back when done. 218610802Srene.dejong@arm.com */ 218710802Srene.dejong@arm.com flashDevice->readMemory(SSDReadInfo.front().filePointer, 218810802Srene.dejong@arm.com SSDReadInfo.front().size, memReadCallback); 218910802Srene.dejong@arm.com } 219010802Srene.dejong@arm.com 219110802Srene.dejong@arm.com} 219210802Srene.dejong@arm.com 219310802Srene.dejong@arm.com 219410802Srene.dejong@arm.com/** 219510802Srene.dejong@arm.com * SSDisk read done 219610802Srene.dejong@arm.com */ 219710802Srene.dejong@arm.com 219810802Srene.dejong@arm.comvoid 219910802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::SSDReadDone() 220010802Srene.dejong@arm.com{ 220110802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "SSD read done at lun %d, Aiming for %d messages," 220210802Srene.dejong@arm.com " %d so far\n", lunID, totalRead, amountOfReadTransfers); 220310802Srene.dejong@arm.com 220410802Srene.dejong@arm.com if (totalRead == amountOfReadTransfers) { 220510802Srene.dejong@arm.com totalRead = 0; 220610802Srene.dejong@arm.com amountOfReadTransfers = 0; 220710802Srene.dejong@arm.com 220810802Srene.dejong@arm.com /**Callback: transferdone*/ 220910802Srene.dejong@arm.com setSignal(); 221010802Srene.dejong@arm.com signalDone->process(); 221110802Srene.dejong@arm.com } 221210802Srene.dejong@arm.com 221310802Srene.dejong@arm.com} 221410802Srene.dejong@arm.com 221510802Srene.dejong@arm.com/** 221610802Srene.dejong@arm.com * Read callback, on the way from the disk to the DMA. Called by the flash 221710802Srene.dejong@arm.com * layer. Intermediate step to the host layer 221810802Srene.dejong@arm.com */ 221910802Srene.dejong@arm.comvoid 222010802Srene.dejong@arm.comUFSHostDevice::UFSSCSIDevice::readCallback() 222110802Srene.dejong@arm.com{ 222210802Srene.dejong@arm.com ++amountOfReadTransfers; 222310802Srene.dejong@arm.com 222410802Srene.dejong@arm.com /**Callback; make sure data is transfered upstream: 222510802Srene.dejong@arm.com * UFSHostDevice::readCallback 222610802Srene.dejong@arm.com */ 222710802Srene.dejong@arm.com setReadSignal(); 222810802Srene.dejong@arm.com deviceReadCallback->process(); 222910802Srene.dejong@arm.com 223010802Srene.dejong@arm.com //Are we done yet? 223110802Srene.dejong@arm.com SSDReadDone(); 223210802Srene.dejong@arm.com} 223310802Srene.dejong@arm.com 223410802Srene.dejong@arm.com/** 223510802Srene.dejong@arm.com * Read callback, on the way from the disk to the DMA. Called by the UFSSCSI 223610802Srene.dejong@arm.com * layer. 223710802Srene.dejong@arm.com */ 223810802Srene.dejong@arm.com 223910802Srene.dejong@arm.comvoid 224010802Srene.dejong@arm.comUFSHostDevice::readCallback() 224110802Srene.dejong@arm.com{ 224210802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Read Callback\n"); 224310802Srene.dejong@arm.com uint8_t this_lun = 0; 224410802Srene.dejong@arm.com 224510802Srene.dejong@arm.com //while we haven't found the right lun, keep searching 224610802Srene.dejong@arm.com while((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedRead()) 224710802Srene.dejong@arm.com ++this_lun; 224810802Srene.dejong@arm.com 224910802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Found LUN %d messages pending for clean: %d\n", 225010802Srene.dejong@arm.com this_lun, SSDReadPending.size()); 225110802Srene.dejong@arm.com 225210802Srene.dejong@arm.com if (this_lun < lunAvail) { 225310802Srene.dejong@arm.com //Clear signal. 225410802Srene.dejong@arm.com UFSDevice[this_lun]->clearReadSignal(); 225510802Srene.dejong@arm.com SSDReadPending.push_back(UFSDevice[this_lun]->SSDReadInfo.front()); 225610802Srene.dejong@arm.com UFSDevice[this_lun]->SSDReadInfo.pop_front(); 225710802Srene.dejong@arm.com readGarbageEventQueue.push_back(this); 225810802Srene.dejong@arm.com 225910802Srene.dejong@arm.com //make sure the queue is popped a the end of the dma transaction 226010802Srene.dejong@arm.com readDevice(false, SSDReadPending.front().offset, 226110802Srene.dejong@arm.com SSDReadPending.front().size, 226210802Srene.dejong@arm.com &SSDReadPending.front().buffer[0], false, 226310802Srene.dejong@arm.com &readGarbageEventQueue.back()); 226410802Srene.dejong@arm.com 226510802Srene.dejong@arm.com /**stats*/ 226610802Srene.dejong@arm.com ++stats.totalReadDiskTransactions; 226710802Srene.dejong@arm.com } 226810802Srene.dejong@arm.com else 226910802Srene.dejong@arm.com panic("no read finished in tick %d\n", curTick()); 227010802Srene.dejong@arm.com} 227110802Srene.dejong@arm.com 227210802Srene.dejong@arm.com/** 227310802Srene.dejong@arm.com * After a disk read DMA transfer, the structure needs to be freed. This is 227410802Srene.dejong@arm.com * done in this function. 227510802Srene.dejong@arm.com */ 227610802Srene.dejong@arm.comvoid 227710802Srene.dejong@arm.comUFSHostDevice::readGarbage() 227810802Srene.dejong@arm.com{ 227910802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "Clean read data, %d\n", SSDReadPending.size()); 228010802Srene.dejong@arm.com SSDReadPending.pop_front(); 228110802Srene.dejong@arm.com readGarbageEventQueue.pop_front(); 228210802Srene.dejong@arm.com} 228310802Srene.dejong@arm.com 228410802Srene.dejong@arm.com/** 228510802Srene.dejong@arm.com * Serialize; needed to make checkpoints 228610802Srene.dejong@arm.com */ 228710802Srene.dejong@arm.com 228810802Srene.dejong@arm.comvoid 228910905Sandreas.sandberg@arm.comUFSHostDevice::serialize(CheckpointOut &cp) const 229010802Srene.dejong@arm.com{ 229110905Sandreas.sandberg@arm.com DmaDevice::serialize(cp); 229210905Sandreas.sandberg@arm.com 229310905Sandreas.sandberg@arm.com const uint8_t* temp_HCI_mem = reinterpret_cast<const uint8_t*>(&UFSHCIMem); 229410802Srene.dejong@arm.com SERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem)); 229510802Srene.dejong@arm.com 229610802Srene.dejong@arm.com uint32_t lun_avail = lunAvail; 229710802Srene.dejong@arm.com SERIALIZE_SCALAR(lun_avail); 229810802Srene.dejong@arm.com} 229910802Srene.dejong@arm.com 230010802Srene.dejong@arm.com 230110802Srene.dejong@arm.com/** 230210802Srene.dejong@arm.com * Unserialize; needed to restore from checkpoints 230310802Srene.dejong@arm.com */ 230410802Srene.dejong@arm.com 230510802Srene.dejong@arm.comvoid 230610905Sandreas.sandberg@arm.comUFSHostDevice::unserialize(CheckpointIn &cp) 230710802Srene.dejong@arm.com{ 230810905Sandreas.sandberg@arm.com DmaDevice::unserialize(cp); 230910802Srene.dejong@arm.com uint8_t* temp_HCI_mem = reinterpret_cast<uint8_t*>(&UFSHCIMem); 231010802Srene.dejong@arm.com UNSERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem)); 231110802Srene.dejong@arm.com 231210802Srene.dejong@arm.com uint32_t lun_avail; 231310802Srene.dejong@arm.com UNSERIALIZE_SCALAR(lun_avail); 231410802Srene.dejong@arm.com assert(lunAvail == lun_avail); 231510802Srene.dejong@arm.com} 231610802Srene.dejong@arm.com 231710802Srene.dejong@arm.com 231810802Srene.dejong@arm.com/** 231910802Srene.dejong@arm.com * Drain; needed to enable checkpoints 232010802Srene.dejong@arm.com */ 232110802Srene.dejong@arm.com 232210913Sandreas.sandberg@arm.comDrainState 232310913Sandreas.sandberg@arm.comUFSHostDevice::drain() 232410802Srene.dejong@arm.com{ 232510802Srene.dejong@arm.com if (UFSHCIMem.TRUTRLDBR) { 232610802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "UFSDevice is draining...\n"); 232710913Sandreas.sandberg@arm.com return DrainState::Draining; 232810802Srene.dejong@arm.com } else { 232910802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "UFSDevice drained\n"); 233010913Sandreas.sandberg@arm.com return DrainState::Drained; 233110802Srene.dejong@arm.com } 233210802Srene.dejong@arm.com} 233310802Srene.dejong@arm.com 233410802Srene.dejong@arm.com/** 233510802Srene.dejong@arm.com * Checkdrain; needed to enable checkpoints 233610802Srene.dejong@arm.com */ 233710802Srene.dejong@arm.com 233810802Srene.dejong@arm.comvoid 233910802Srene.dejong@arm.comUFSHostDevice::checkDrain() 234010802Srene.dejong@arm.com{ 234110913Sandreas.sandberg@arm.com if (drainState() != DrainState::Draining) 234210802Srene.dejong@arm.com return; 234310802Srene.dejong@arm.com 234410802Srene.dejong@arm.com if (UFSHCIMem.TRUTRLDBR) { 234510802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "UFSDevice is still draining; with %d active" 234610802Srene.dejong@arm.com " doorbells\n", activeDoorbells); 234710802Srene.dejong@arm.com } else { 234810802Srene.dejong@arm.com DPRINTF(UFSHostDevice, "UFSDevice is done draining\n"); 234910913Sandreas.sandberg@arm.com signalDrainDone(); 235010802Srene.dejong@arm.com } 235110802Srene.dejong@arm.com} 2352