PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
scache.c
1//---------------------------------------------------------------------------
2// File name: scache.c
3//---------------------------------------------------------------------------
4/*
5 * scache.c - USB Mass storage driver for PS2
6 *
7 * (C) 2004, Marek Olejnik (ole00@post.cz)
8 * (C) 2004 Hermes (support for sector sizes from 512 to 4096 bytes)
9 *
10 * Sector cache
11 *
12 * See the file LICENSE included with this distribution for licensing terms.
13 */
14//---------------------------------------------------------------------------
15#include <stdio.h>
16
17#ifdef WIN32
18#include <memory.h>
19#include <string.h>
20#include <stdlib.h>
21#else
22#include <tamtypes.h>
23#include <sysmem.h>
24#endif
25
26// #define SCACHE_RECORD_STATS 1
27
28#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
29#include <bdm.h>
30#endif
31#ifdef BUILDING_USBHDFSD
32#include <usbhdfsd.h>
33#endif /* BUILDING_USBHDFSD */
34#include "usbhd_common.h"
35#ifdef BUILDING_USBHDFSD
36#include "mass_stor.h"
37#endif /* BUILDING_USBHDFSD */
38#ifdef BUILDING_IEEE1394_DISK
39#include "sbp2_disk.h"
40#include "scsi.h"
41#endif /* BUILDING_IEEE1394_DISK */
42#include "scache.h"
43
44//---------------------------------------------------------------------------
45#ifdef BUILDING_USBHDFSD
46#define READ_SECTOR mass_stor_readSector
47#define WRITE_SECTOR mass_stor_writeSector
48#define DEV_ACCESSOR(d) ((d)->dev)
49#define DEVID_ACCESSOR(d) ((d)->dev->devId)
50#endif /* BUILDING_USBHDFSD */
51#ifdef BUILDING_IEEE1394_DISK
52#define READ_SECTOR scsiReadSector
53#define WRITE_SECTOR scsiWriteSector
54#define DEV_ACCESSOR(d) ((d)->dev)
55#define DEVID_ACCESSOR(d) ((d)->dev->nodeID)
56#endif /* BUILDING_IEEE1394_DISK */
57#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
58#define READ_SECTOR(d, s, a, c) (d)->bd->read((d)->bd, s, a, c)
59#define WRITE_SECTOR(d, s, a, c) (d)->bd->write((d)->bd, s, a, c)
60#define DEV_ACCESSOR(d) (d)
61#define DEVID_ACCESSOR(d) ((d)->bd->devNr)
62#endif
63
64// #define DEBUG //comment out this line when not debugging
65
66#include "mass_debug.h"
67
68#ifdef BUILDING_USBHDFSD
69// when the flushCounter reaches FLUSH_TRIGGER then flushSectors is called
70// #define FLUSH_TRIGGER 16
71
72static int scache_flushSector(cache_set *cache, int index);
73#endif /* BUILDING_USBHDFSD */
74
75//---------------------------------------------------------------------------
76static void initRecords(cache_set *cache)
77{
78 unsigned int i;
79
80 for (i = 0; i < CACHE_SIZE; i++) {
81 cache->rec[i].sector = 0xFFFFFFF0;
82 cache->rec[i].tax = 0;
83 cache->rec[i].writeDirty = 0;
84 }
85
86 cache->writeFlag = 0;
87}
88
89//---------------------------------------------------------------------------
90/* search cache records for the sector number stored in cache
91 returns cache record (slot) number
92 */
93static int getSlot(cache_set *cache, unsigned int sector)
94{
95 int i;
96
97 for (i = 0; i < CACHE_SIZE; i++) {
98 if (sector >= cache->rec[i].sector && sector < (cache->rec[i].sector + cache->indexLimit)) {
99 return i;
100 }
101 }
102 return -1;
103}
104
105//---------------------------------------------------------------------------
106/* search cache records for the sector number stored in cache */
107static int getIndexRead(cache_set *cache, unsigned int sector)
108{
109 unsigned int i;
110 int index = -1;
111
112 for (i = 0; i < CACHE_SIZE; i++) {
113 if (sector >= cache->rec[i].sector && sector < (cache->rec[i].sector + cache->indexLimit)) {
114 if (cache->rec[i].tax < 0)
115 cache->rec[i].tax = 0;
116 cache->rec[i].tax += 2;
117 index = i;
118 }
119 if (cache->rec[i].tax > 1)
120 {
121 cache->rec[i].tax--; // apply tax penalty
122 }
123 }
124 if (index < 0)
125 return index;
126 else
127 return ((index * cache->indexLimit) + (sector - cache->rec[index].sector));
128}
129
130//---------------------------------------------------------------------------
131/* select the best record where to store new sector */
132static int getIndexWrite(cache_set *cache, unsigned int sector)
133{
134 int minTax = 0x0FFFFFFF;
135 unsigned int i, index = 0;
136
137 for (i = 0; i < CACHE_SIZE; i++) {
138 if (cache->rec[i].tax < minTax) {
139 index = i;
140 minTax = cache->rec[i].tax;
141 }
142 }
143
144 // this sector is dirty - we need to flush it first
145#ifdef BUILDING_USBHDFSD
146 {
147 int ret;
148 ret = scache_flushSector(cache, index);
149 if (ret != 1)
150 return ret;
151 }
152#else
153 if (cache->rec[index].writeDirty) {
154 int ret;
155
156 XPRINTF("scache: getIndexWrite: sector is dirty : %d index=%d \n", cache->rec[index].sector, index);
157 ret = WRITE_SECTOR(DEV_ACCESSOR(cache), cache->rec[index].sector, cache->sectorBuf + (index * BLOCK_SIZE), BLOCK_SIZE / cache->sectorSize);
158 cache->rec[index].writeDirty = 0;
159 // TODO - error handling
160 if (ret < 0) {
161 M_PRINTF("scache: ERROR writing sector to disk! sector=%u\n", sector);
162 }
163 }
164#endif
165 cache->rec[index].tax += 2;
166 cache->rec[index].sector = sector;
167
168 return index * cache->indexLimit;
169}
170
171//---------------------------------------------------------------------------
172/*
173 flush dirty sectors
174 */
175#ifdef BUILDING_USBHDFSD
176static int scache_flushSector(cache_set *cache, int index)
177{
178 if (cache->rec[index].writeDirty) {
179 int ret;
180
181 XPRINTF("scache: flushSector dirty index=%d sector=%u \n", index, cache->rec[index].sector);
182 ret = WRITE_SECTOR(DEV_ACCESSOR(cache), cache->rec[index].sector, cache->sectorBuf + (index * BLOCK_SIZE), BLOCK_SIZE / cache->sectorSize);
183 if (ret < 0) {
184 M_PRINTF("scache: ERROR writing sector to disk! sector=%u\n", cache->rec[index].sector);
185 return ret;
186 }
187
188 cache->rec[index].writeDirty = 0;
189 }
190 return 1;
191}
192#endif /* BUILDING_USBHDFSD */
193
194int scache_flushSectors(cache_set *cache)
195{
196 unsigned int i;
197 int counter = 0;
198
199 XPRINTF("cache: flushSectors devId = %i \n", DEVID_ACCESSOR(cache));
200
201 XPRINTF("scache: flushSectors writeFlag=%d\n", cache->writeFlag);
202 // no write operation occured since last flush
203 if (cache->writeFlag == 0) {
204 return 0;
205 }
206
207 for (i = 0; i < CACHE_SIZE; i++) {
208 int ret;
209#ifdef BUILDING_USBHDFSD
210 if ((ret = scache_flushSector(cache, i)) >= 0)
211#else
212 if (cache->rec[i].writeDirty)
213#endif
214 {
215#ifndef BUILDING_USBHDFSD
216 XPRINTF("scache: flushSectors dirty index=%d sector=%u \n", i, cache->rec[i].sector);
217 ret = WRITE_SECTOR(DEV_ACCESSOR(cache), cache->rec[i].sector, cache->sectorBuf + (i * BLOCK_SIZE), BLOCK_SIZE);
218#if defined(BUILDING_IEEE1394_DISK) || defined(BUILDING_USBHDFSD)
219 cache->rec[i].writeDirty = 0;
220#endif
221 // TODO - error handling
222 if (ret < 0) {
223 M_PRINTF("scache: ERROR writing sector to disk! sector=%d\n", cache->rec[i].sector);
224 return ret;
225 }
226#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
227 cache->rec[i].writeDirty = 0;
228#endif
229#endif /* BUILDING_USBHDFSD */
230 counter++;
231 }
232#ifdef BUILDING_USBHDFSD
233 else
234 return ret;
235#endif /* BUILDING_USBHDFSD */
236 }
237 cache->writeFlag = 0;
238 return counter;
239}
240
241//---------------------------------------------------------------------------
242int scache_readSector(cache_set *cache, unsigned int sector, void **buf)
243{
244 int index; // index is given in single sectors not octal sectors
245 int ret;
246 unsigned int alignedSector;
247
248 if (cache != NULL) {
249 XPRINTF("cache: readSector devId = %i %p sector = %u \n", DEVID_ACCESSOR(cache), cache, sector);
250 }
251 if (cache == NULL) {
252 M_PRINTF("cache: devId cache not created \n");
253 return -1;
254 }
255
256#ifdef SCACHE_RECORD_STATS
257 cache->cacheAccess++;
258#endif
259 index = getIndexRead(cache, sector);
260 XPRINTF("cache: indexRead=%i \n", index);
261 if (index >= 0) { // sector found in cache
262#ifdef SCACHE_RECORD_STATS
263 cache->cacheHits++;
264#endif
265 *buf = cache->sectorBuf + (index * cache->sectorSize);
266 XPRINTF("cache: hit and done reading sector \n");
267
268 return cache->sectorSize;
269 }
270
271 // compute alignedSector - to prevent storage of duplicit sectors in slots
272 alignedSector = (sector / cache->indexLimit) * cache->indexLimit;
273 index = getIndexWrite(cache, alignedSector);
274 XPRINTF("cache: indexWrite=%i slot=%d alignedSector=%u\n", index, index / cache->indexLimit, alignedSector);
275 ret = READ_SECTOR(DEV_ACCESSOR(cache), alignedSector, cache->sectorBuf + (index * cache->sectorSize), BLOCK_SIZE / cache->sectorSize);
276
277 if (ret < 0) {
278 M_PRINTF("scache: ERROR reading sector from disk! sector=%u\n", alignedSector);
279 return ret;
280 }
281 *buf = cache->sectorBuf + (index * cache->sectorSize) + ((sector % cache->indexLimit) * cache->sectorSize);
282 XPRINTF("cache: done reading physical sector \n");
283
284 // write precaution
285 /* cache->flushCounter++;
286 if (cache->flushCounter == FLUSH_TRIGGER) {
287 scache_flushSectors(cache);
288 } */
289
290 return cache->sectorSize;
291}
292
293
294//---------------------------------------------------------------------------
295/* SP193: this function is dangerous if not used correctly.
296 As scache's blocks are aligned to the start of the disk, the clusters of the partition
297 must also be aligned to a multiple of the scache block size.
298 Otherwise, it is possible to cause the adjacent cluster to lose data, if the block spans across more than one cluster.
299*/
300#if 0
301int scache_allocSector(cache_set *cache, unsigned int sector, void **buf)
302{
303 int index; // index is given in single sectors not octal sectors
304 // int ret;
305 unsigned int alignedSector;
306
307 XPRINTF("cache: allocSector devId = %i sector = %u \n", DEVID_ACCESSOR(cache), sector);
308
309 index = getIndexRead(cache, sector);
310 XPRINTF("cache: indexRead=%i \n", index);
311 if (index >= 0) { // sector found in cache
312 *buf = cache->sectorBuf + (index * cache->sectorSize);
313 XPRINTF("cache: hit and done allocating sector \n");
314 return cache->sectorSize;
315 }
316
317 // compute alignedSector - to prevent storage of duplicit sectors in slots
318 alignedSector = (sector / cache->indexLimit) * cache->indexLimit;
319 index = getIndexWrite(cache, alignedSector);
320 XPRINTF("cache: indexWrite=%i \n", index);
321 *buf = cache->sectorBuf + (index * cache->sectorSize) + ((sector % cache->indexLimit) * cache->sectorSize);
322 XPRINTF("cache: done allocating sector\n");
323 return cache->sectorSize;
324}
325#endif
326
327//---------------------------------------------------------------------------
328int scache_writeSector(cache_set *cache, unsigned int sector)
329{
330 int index; // index is given in single sectors not octal sectors
331 // int ret;
332
333 XPRINTF("cache: writeSector devId = %i sector = %u \n", DEVID_ACCESSOR(cache), sector);
334
335 index = getSlot(cache, sector);
336 if (index < 0) { // sector not found in cache
337 M_PRINTF("cache: writeSector: ERROR! the sector is not allocated! \n");
338 return -1;
339 }
340 XPRINTF("cache: slotFound=%i \n", index);
341
342 // prefere written sectors to stay in cache longer than read sectors
343 cache->rec[index].tax += 2;
344
345 // set dirty status
346 cache->rec[index].writeDirty = 1;
347 cache->writeFlag++;
348
349 XPRINTF("cache: done soft writing sector \n");
350
351 // write precaution
352 /* cache->flushCounter++;
353 if (cache->flushCounter == FLUSH_TRIGGER) {
354 scache_flushSectors(devId);
355 } */
356
357 return cache->sectorSize;
358}
359
360#ifdef BUILDING_USBHDFSD
361void scache_invalidate(cache_set *cache, unsigned int sector, int count)
362{
363 int i;
364
365 XPRINTF("cache: invalidate devId = %i sector = %u count = %d \n", DEVID_ACCESSOR(cache), sector, count);
366
367 for (i = 0; i < count; i++, sector++) {
368 int index; // index is given in single sectors not octal sectors
369
370 index = getSlot(cache, sector);
371 if (index >= 0) { // sector found in cache. Write back and invalidate the block it belongs to.
372 scache_flushSector(cache, index);
373
374 cache->rec[index].sector = 0xFFFFFFF0;
375 cache->rec[index].tax = 0;
376 cache->rec[index].writeDirty = 0;
377 }
378 }
379}
380#endif /* BUILDING_USBHDFSD */
381
382//---------------------------------------------------------------------------
383#if defined(BUILDING_USBHDFSD)
384cache_set *scache_init(mass_dev *dev, int sectSize)
385#elif defined(BUILDING_IEEE1394_DISK)
386cache_set *scache_init(struct SBP2Device *dev, int sectSize)
387#else
388cache_set *scache_init(struct block_device *bd)
389#endif
390{
391 cache_set *cache;
392#ifdef BUILDING_USBHDFSD
393 XPRINTF("cache: init devId = %i sectSize = %u \n", dev->devId, sectSize);
394#endif /* BUILDING_USBHDFSD */
395#ifdef BUILDING_IEEE1394_DISK
396 XPRINTF("cache: init devId = %i sectSize = %i \n", dev->nodeID, sectSize);
397#endif /* BUILDING_IEEE1394_DISK */
398
399 cache = malloc(sizeof(cache_set));
400 if (cache == NULL) {
401 M_PRINTF("scache init! Sector cache: can't alloate cache!\n");
402 return NULL;
403 }
404
405 XPRINTF("scache init! \n");
406#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
407 cache->bd = bd;
408#else
409 cache->dev = dev;
410#endif
411
412 cache->sectorBuf = (unsigned char *)malloc(BLOCK_SIZE * CACHE_SIZE);
413 if (cache->sectorBuf == NULL) {
414 M_PRINTF("Sector cache: can't alloate memory of size:%d \n", BLOCK_SIZE * CACHE_SIZE);
415 free(cache);
416 return NULL;
417 }
418 XPRINTF("Sector cache: allocated memory at:%p of size:%d \n", cache->sectorBuf, BLOCK_SIZE * CACHE_SIZE);
419
420 // added by Hermes
421#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
422 cache->sectorSize = bd->sectorSize;
423#else
424 cache->sectorSize = sectSize;
425#endif
426 cache->indexLimit = BLOCK_SIZE / cache->sectorSize; // number of sectors per 1 cache slot
427#ifdef SCACHE_RECORD_STATS
428 cache->cacheAccess = 0;
429 cache->cacheHits = 0;
430#endif
431 XPRINTF("sectorSize: 0x%x\n", cache->sectorSize);
432 initRecords(cache);
433 return cache;
434}
435
436#ifdef SCACHE_RECORD_STATS
437//---------------------------------------------------------------------------
438void scache_getStat(cache_set *cache, unsigned int *access, unsigned int *hits)
439{
440 *access = cache->cacheAccess;
441 *hits = cache->cacheHits;
442}
443#endif
444
445//---------------------------------------------------------------------------
446void scache_kill(cache_set *cache) // dlanor: added for disconnection events (flush impossible)
447{
448 XPRINTF("cache: kill devId = %i \n", DEVID_ACCESSOR(cache));
449 if (cache->sectorBuf != NULL) {
450 free(cache->sectorBuf);
451 cache->sectorBuf = NULL;
452 }
453 free(cache);
454}
455//---------------------------------------------------------------------------
456void scache_close(cache_set *cache)
457{
458 XPRINTF("cache: close devId = %i \n", DEVID_ACCESSOR(cache));
459 scache_flushSectors(cache);
460 scache_kill(cache);
461}
462//---------------------------------------------------------------------------
463// End of file: scache.c
464//---------------------------------------------------------------------------
u32 count
start sector of fragmented bd/file