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