1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6
7 /*********************************************************************/
8
9 OSSTATUS __fastcall WCacheCheckLimits(IN PW_CACHE Cache,
10 IN PVOID Context,
11 IN lba_t ReqLba,
12 IN ULONG BCount);
13
14 OSSTATUS __fastcall WCacheCheckLimitsRAM(IN PW_CACHE Cache,
15 IN PVOID Context,
16 IN lba_t ReqLba,
17 IN ULONG BCount);
18
19 OSSTATUS __fastcall WCacheCheckLimitsRW(IN PW_CACHE Cache,
20 IN PVOID Context,
21 IN lba_t ReqLba,
22 IN ULONG BCount);
23
24 OSSTATUS __fastcall WCacheCheckLimitsR(IN PW_CACHE Cache,
25 IN PVOID Context,
26 IN lba_t ReqLba,
27 IN ULONG BCount);
28
29 VOID __fastcall WCachePurgeAllRW(IN PW_CACHE Cache,
30 IN PVOID Context);
31
32 VOID __fastcall WCacheFlushAllRW(IN PW_CACHE Cache,
33 IN PVOID Context);
34
35 VOID __fastcall WCachePurgeAllR(IN PW_CACHE Cache,
36 IN PVOID Context);
37
38 OSSTATUS __fastcall WCacheDecodeFlags(IN PW_CACHE Cache,
39 IN ULONG Flags);
40
41 #define ASYNC_STATE_NONE 0
42 #define ASYNC_STATE_READ_PRE 1
43 #define ASYNC_STATE_READ 2
44 #define ASYNC_STATE_WRITE_PRE 3
45 #define ASYNC_STATE_WRITE 4
46 #define ASYNC_STATE_DONE 5
47
48 #define ASYNC_CMD_NONE 0
49 #define ASYNC_CMD_READ 1
50 #define ASYNC_CMD_UPDATE 2
51
52 #define WCACHE_MAX_CHAIN (0x10)
53
54 #define MEM_WCCTX_TAG 'xtCW'
55 #define MEM_WCFRM_TAG 'rfCW'
56 #define MEM_WCBUF_TAG 'fbCW'
57
58 #define USE_WC_PRINT
59
60 #ifdef USE_WC_PRINT
61 #define WcPrint UDFPrint
62 #else
63 #define WcPrint(x) {;}
64 #endif
65
66 typedef struct _W_CACHE_ASYNC {
67 UDF_PH_CALL_CONTEXT PhContext;
68 ULONG State;
69 ULONG Cmd;
70 PW_CACHE Cache;
71 PVOID Buffer;
72 PVOID Buffer2;
73 SIZE_T TransferredBytes;
74 ULONG BCount;
75 lba_t Lba;
76 struct _W_CACHE_ASYNC* NextWContext;
77 struct _W_CACHE_ASYNC* PrevWContext;
78 } W_CACHE_ASYNC, *PW_CACHE_ASYNC;
79
80 VOID
81 WCacheUpdatePacketComplete(
82 IN PW_CACHE Cache, // pointer to the Cache Control structure
83 IN PVOID Context, // user-supplied context for IO callbacks
84 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context
85 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context
86 IN BOOLEAN FreePacket = TRUE
87 );
88
89 /*********************************************************************/
90 ULONG WCache_random;
91
92 /*
93 WCacheInit__() fills all necesary fileds in passed in PW_CACHE Cache
94 structure, allocates memory and synchronization resources.
95 Cacheable area is subdiveded on Frames - contiguous sets of blocks.
96 Internally each Frame is an array of pointers and attributes of cached
97 Blocks. To optimize memory usage WCache keeps in memory limited number
98 of frames (MaxFrames).
99 Frame length (number of Blocks) must be be a power of 2 and aligned on
100 minimum writeable block size - Packet.
101 Packet size must be a power of 2 (2, 4, 8, 16, etc.).
102 Each cached Block belongs to one of the Frames. To optimize memory usage
103 WCache keeps in memory limited number of Blocks (MaxBlocks). Block size
104 must be a power of 2.
105 WCache splits low-level request(s) into some parts if requested data length
106 exceeds MaxBytesToRead.
107 If requested data length exceeds maximum cache size WCache makes
108 recursive calls to read/write routines with shorter requests
109
110 WCacheInit__() returns initialization status. If initialization failed,
111 all allocated memory and resources are automaticelly freed.
112
113 Public routine
114 */
115 OSSTATUS
WCacheInit__(IN PW_CACHE Cache,IN ULONG MaxFrames,IN ULONG MaxBlocks,IN SIZE_T MaxBytesToRead,IN ULONG PacketSizeSh,IN ULONG BlockSizeSh,IN ULONG BlocksPerFrameSh,IN lba_t FirstLba,IN lba_t LastLba,IN ULONG Mode,IN ULONG Flags,IN ULONG FramesToKeepFree,IN PWRITE_BLOCK WriteProc,IN PREAD_BLOCK ReadProc,IN PWRITE_BLOCK_ASYNC WriteProcAsync,IN PREAD_BLOCK_ASYNC ReadProcAsync,IN PCHECK_BLOCK CheckUsedProc,IN PUPDATE_RELOC UpdateRelocProc,IN PWC_ERROR_HANDLER ErrorHandlerProc)116 WCacheInit__(
117 IN PW_CACHE Cache, // pointer to the Cache Control structure to be initialized
118 IN ULONG MaxFrames, // maximum number of Frames to be kept in memory
119 // simultaneously
120 IN ULONG MaxBlocks, // maximum number of Blocks to be kept in memory
121 // simultaneously
122 IN SIZE_T MaxBytesToRead, // maximum IO length (split boundary)
123 IN ULONG PacketSizeSh, // number of blocks in packet (bit shift)
124 // Packes size = 2^PacketSizeSh
125 IN ULONG BlockSizeSh, // Block size (bit shift)
126 // Block size = 2^BlockSizeSh
127 IN ULONG BlocksPerFrameSh,// number of blocks in Frame (bit shift)
128 // Frame size = 2^BlocksPerFrameSh
129 IN lba_t FirstLba, // Logical Block Address (LBA) of the 1st block
130 // in cacheable area
131 IN lba_t LastLba, // Logical Block Address (LBA) of the last block
132 // in cacheable area
133 IN ULONG Mode, // media mode:
134 // WCACHE_MODE_ROM
135 // WCACHE_MODE_RW
136 // WCACHE_MODE_R
137 // WCACHE_MODE_RAM
138 // the following modes are planned to be implemented:
139 // WCACHE_MODE_EWR
140 IN ULONG Flags, // cache mode flags:
141 // WCACHE_CACHE_WHOLE_PACKET
142 // read long (Packet-sized) blocks of
143 // data from media
144 IN ULONG FramesToKeepFree,
145 // number of Frames to be flushed & purged from cache
146 // when Frame counter reaches top-limit and allocation
147 // of a new Frame required
148 IN PWRITE_BLOCK WriteProc,
149 // pointer to synchronous physical write call-back routine
150 IN PREAD_BLOCK ReadProc,
151 // pointer to synchronous physical read call-back routine
152 IN PWRITE_BLOCK_ASYNC WriteProcAsync,
153 // pointer to _asynchronous_ physical write call-back routine
154 // currently must be set to NULL because async support
155 // is not completly implemented
156 IN PREAD_BLOCK_ASYNC ReadProcAsync,
157 // pointer to _asynchronous_ physical read call-back routine
158 // must be set to NULL (see above)
159 IN PCHECK_BLOCK CheckUsedProc,
160 // pointer to call-back routine that checks whether the Block
161 // specified (by LBA) is allocated for some data or should
162 // be treated as unused (and thus, zero-filled).
163 // Is used to avoid physical reads and writes from/to such Blocks
164 IN PUPDATE_RELOC UpdateRelocProc,
165 // pointer to call-back routine that updates caller's
166 // relocation table _after_ physical write (append) in WORM
167 // (WCACHE_MODE_R) mode. WCache sends original and new
168 // (derived from last LBA) logical addresses to this routine
169 IN PWC_ERROR_HANDLER ErrorHandlerProc
170 )
171 {
172 ULONG l1, l2, l3;
173 ULONG PacketSize = (1) << PacketSizeSh;
174 ULONG BlockSize = (1) << BlockSizeSh;
175 ULONG BlocksPerFrame = (1) << BlocksPerFrameSh;
176 OSSTATUS RC = STATUS_SUCCESS;
177 LARGE_INTEGER rseed;
178 ULONG res_init_flags = 0;
179
180 #define WCLOCK_RES 1
181
182 _SEH2_TRY {
183 // check input parameters
184 if(Mode == WCACHE_MODE_R) {
185 UDFPrint(("Disable Async-Write for WORM media\n"));
186 WriteProcAsync = NULL;
187 }
188 if((MaxBlocks % PacketSize) || !MaxBlocks) {
189 UDFPrint(("Total number of sectors must be packet-size-aligned\n"));
190 try_return(RC = STATUS_INVALID_PARAMETER);
191 }
192 if(BlocksPerFrame % PacketSize) {
193 UDFPrint(("Number of sectors per Frame must be packet-size-aligned\n"));
194 try_return(RC = STATUS_INVALID_PARAMETER);
195 }
196 if(!ReadProc) {
197 UDFPrint(("Read routine pointer must be valid\n"));
198 try_return(RC = STATUS_INVALID_PARAMETER);
199 }
200 if(FirstLba >= LastLba) {
201 UDFPrint(("Invalid cached area parameters: (%x - %x)\n",FirstLba, LastLba));
202 try_return(RC = STATUS_INVALID_PARAMETER);
203 }
204 if(!MaxFrames) {
205 UDFPrint(("Total frame number must be non-zero\n",FirstLba, LastLba));
206 try_return(RC = STATUS_INVALID_PARAMETER);
207 }
208 if(Mode > WCACHE_MODE_MAX) {
209 UDFPrint(("Invalid media mode. Should be 0-%x\n",WCACHE_MODE_MAX));
210 try_return(RC = STATUS_INVALID_PARAMETER);
211 }
212 if(FramesToKeepFree >= MaxFrames/2) {
213 UDFPrint(("Invalid FramesToKeepFree (%x). Should be Less or equal to MaxFrames/2 (%x)\n", FramesToKeepFree, MaxFrames/2));
214 try_return(RC = STATUS_INVALID_PARAMETER);
215 }
216 // check 'features'
217 if(!WriteProc) {
218 UDFPrint(("Write routine not specified\n"));
219 UDFPrint(("Read-only mode enabled\n"));
220 }
221 MaxBlocks = max(MaxBlocks, BlocksPerFrame*3);
222 // initialize required structures
223 // we'll align structure size on system page size to
224 // avoid system crashes caused by pool fragmentation
225 if(!(Cache->FrameList =
226 (PW_CACHE_FRAME)MyAllocatePoolTag__(NonPagedPool, l1 = (((LastLba >> BlocksPerFrameSh)+1)*sizeof(W_CACHE_FRAME)), MEM_WCFRM_TAG) )) {
227 UDFPrint(("Cache init err 1\n"));
228 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
229 }
230 if(!(Cache->CachedBlocksList =
231 (PULONG)MyAllocatePoolTag__(NonPagedPool, l2 = ((MaxBlocks+2)*sizeof(lba_t)), MEM_WCFRM_TAG) )) {
232 UDFPrint(("Cache init err 2\n"));
233 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
234 }
235 if(!(Cache->CachedModifiedBlocksList =
236 (PULONG)MyAllocatePoolTag__(NonPagedPool, l2, MEM_WCFRM_TAG) )) {
237 UDFPrint(("Cache init err 3\n"));
238 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
239 }
240 if(!(Cache->CachedFramesList =
241 (PULONG)MyAllocatePoolTag__(NonPagedPool, l3 = ((MaxFrames+2)*sizeof(lba_t)), MEM_WCFRM_TAG) )) {
242 UDFPrint(("Cache init err 4\n"));
243 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
244 }
245 RtlZeroMemory(Cache->FrameList, l1);
246 RtlZeroMemory(Cache->CachedBlocksList, l2);
247 RtlZeroMemory(Cache->CachedModifiedBlocksList, l2);
248 RtlZeroMemory(Cache->CachedFramesList, l3);
249 // remember all useful parameters
250 Cache->BlocksPerFrame = BlocksPerFrame;
251 Cache->BlocksPerFrameSh = BlocksPerFrameSh;
252 Cache->BlockCount = 0;
253 Cache->MaxBlocks = MaxBlocks;
254 Cache->MaxBytesToRead = MaxBytesToRead;
255 Cache->FrameCount = 0;
256 Cache->MaxFrames = MaxFrames;
257 Cache->PacketSize = PacketSize;
258 Cache->PacketSizeSh = PacketSizeSh;
259 Cache->BlockSize = BlockSize;
260 Cache->BlockSizeSh = BlockSizeSh;
261 Cache->WriteCount = 0;
262 Cache->FirstLba = FirstLba;
263 Cache->LastLba = LastLba;
264 Cache->Mode = Mode;
265
266 if(!OS_SUCCESS(RC = WCacheDecodeFlags(Cache, Flags))) {
267 return RC;
268 }
269
270 Cache->FramesToKeepFree = FramesToKeepFree;
271 Cache->WriteProc = WriteProc;
272 Cache->ReadProc = ReadProc;
273 Cache->WriteProcAsync = WriteProcAsync;
274 Cache->ReadProcAsync = ReadProcAsync;
275 Cache->CheckUsedProc = CheckUsedProc;
276 Cache->UpdateRelocProc = UpdateRelocProc;
277 Cache->ErrorHandlerProc = ErrorHandlerProc;
278 // init permanent tmp buffers
279 if(!(Cache->tmp_buff =
280 (PCHAR)MyAllocatePoolTag__(NonPagedPool, PacketSize*BlockSize, MEM_WCFRM_TAG))) {
281 UDFPrint(("Cache init err 5.W\n"));
282 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
283 }
284 if(!(Cache->tmp_buff_r =
285 (PCHAR)MyAllocatePoolTag__(NonPagedPool, PacketSize*BlockSize, MEM_WCFRM_TAG))) {
286 UDFPrint(("Cache init err 5.R\n"));
287 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
288 }
289 if(!(Cache->reloc_tab =
290 (PULONG)MyAllocatePoolTag__(NonPagedPool, Cache->PacketSize*sizeof(ULONG), MEM_WCFRM_TAG))) {
291 UDFPrint(("Cache init err 6\n"));
292 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
293 }
294 if(!OS_SUCCESS(RC = ExInitializeResourceLite(&(Cache->WCacheLock)))) {
295 UDFPrint(("Cache init err (res)\n"));
296 try_return(RC);
297 }
298 res_init_flags |= WCLOCK_RES;
299 KeQuerySystemTime((PLARGE_INTEGER)(&rseed));
300 WCache_random = rseed.LowPart;
301
302 try_exit: NOTHING;
303
304 } _SEH2_FINALLY {
305
306 if(!OS_SUCCESS(RC)) {
307 if(res_init_flags & WCLOCK_RES)
308 ExDeleteResourceLite(&(Cache->WCacheLock));
309 if(Cache->FrameList)
310 MyFreePool__(Cache->FrameList);
311 if(Cache->CachedBlocksList)
312 MyFreePool__(Cache->CachedBlocksList);
313 if(Cache->CachedModifiedBlocksList)
314 MyFreePool__(Cache->CachedModifiedBlocksList);
315 if(Cache->CachedFramesList)
316 MyFreePool__(Cache->CachedFramesList);
317 if(Cache->tmp_buff_r)
318 MyFreePool__(Cache->tmp_buff_r);
319 if(Cache->tmp_buff)
320 MyFreePool__(Cache->tmp_buff);
321 if(Cache->reloc_tab)
322 MyFreePool__(Cache->reloc_tab);
323 RtlZeroMemory(Cache, sizeof(W_CACHE));
324 } else {
325 Cache->Tag = 0xCAC11E00;
326 }
327
328 } _SEH2_END;
329
330 return RC;
331 } // end WCacheInit__()
332
333 /*
334 WCacheRandom() - just a random generator
335 Returns random LONGLONG number
336 Internal routine
337 */
338 LONGLONG
WCacheRandom(VOID)339 WCacheRandom(VOID)
340 {
341 WCache_random = (WCache_random * 0x8088405 + 1);
342 return WCache_random;
343 } // end WCacheRandom()
344
345 /*
346 WCacheFindLbaToRelease() finds Block to be flushed and purged from cache
347 Returns random LBA
348 Internal routine
349 */
350 lba_t
351 __fastcall
WCacheFindLbaToRelease(IN PW_CACHE Cache)352 WCacheFindLbaToRelease(
353 IN PW_CACHE Cache
354 )
355 {
356 if(!(Cache->BlockCount))
357 return WCACHE_INVALID_LBA;
358 return(Cache->CachedBlocksList[((ULONG)WCacheRandom() % Cache->BlockCount)]);
359 } // end WCacheFindLbaToRelease()
360
361 /*
362 WCacheFindModifiedLbaToRelease() finds Block to be flushed and purged from cache.
363 This routine looks for Blocks among modified ones
364 Returns random LBA (nodified)
365 Internal routine
366 */
367 lba_t
368 __fastcall
WCacheFindModifiedLbaToRelease(IN PW_CACHE Cache)369 WCacheFindModifiedLbaToRelease(
370 IN PW_CACHE Cache
371 )
372 {
373 if(!(Cache->WriteCount))
374 return WCACHE_INVALID_LBA;
375 return(Cache->CachedModifiedBlocksList[((ULONG)WCacheRandom() % Cache->WriteCount)]);
376 } // end WCacheFindModifiedLbaToRelease()
377
378 /*
379 WCacheFindFrameToRelease() finds Frame to be flushed and purged with all
380 Blocks (from this Frame) from cache
381 Returns random Frame number
382 Internal routine
383 */
384 lba_t
385 __fastcall
WCacheFindFrameToRelease(IN PW_CACHE Cache)386 WCacheFindFrameToRelease(
387 IN PW_CACHE Cache
388 )
389 {
390 ULONG i, j;
391 ULONG frame = 0;
392 ULONG prev_uc = -1;
393 ULONG uc = -1;
394 lba_t lba;
395 BOOLEAN mod = FALSE;
396
397 if(!(Cache->FrameCount))
398 return 0;
399 /*
400 return(Cache->CachedFramesList[((ULONG)WCacheRandom() % Cache->FrameCount)]);
401 */
402
403 for(i=0; i<Cache->FrameCount; i++) {
404
405 j = Cache->CachedFramesList[i];
406
407 mod |= (Cache->FrameList[j].UpdateCount != 0);
408 uc = Cache->FrameList[j].UpdateCount*32 + Cache->FrameList[j].AccessCount;
409
410 if(prev_uc > uc) {
411 prev_uc = uc;
412 frame = j;
413 }
414 }
415 if(!mod) {
416 frame = Cache->CachedFramesList[((ULONG)WCacheRandom() % Cache->FrameCount)];
417 lba = frame << Cache->BlocksPerFrameSh;
418 WcPrint(("WC:-frm %x\n", lba));
419 } else {
420 lba = frame << Cache->BlocksPerFrameSh;
421 WcPrint(("WC:-frm(mod) %x\n", lba));
422 for(i=0; i<Cache->FrameCount; i++) {
423
424 j = Cache->CachedFramesList[i];
425 Cache->FrameList[j].UpdateCount = (Cache->FrameList[j].UpdateCount*2)/3;
426 Cache->FrameList[j].AccessCount = (Cache->FrameList[j].AccessCount*3)/4;
427 }
428 }
429 return frame;
430 } // end WCacheFindFrameToRelease()
431
432 /*
433 WCacheGetSortedListIndex() returns index of searched Lba
434 (Lba is ULONG in sorted array) or index of minimal cached Lba
435 greater than searched.
436 If requested Lba is less than minimum cached, 0 is returned.
437 If requested Lba is greater than maximum cached, BlockCount value
438 is returned.
439 Internal routine
440 */
441
442 #ifdef _MSC_VER
443 #pragma warning(push)
444 #pragma warning(disable:4035) // re-enable below
445 #endif
446
447 ULONG
448 //__fastcall
WCacheGetSortedListIndex(IN ULONG BlockCount,IN lba_t * List,IN lba_t Lba)449 WCacheGetSortedListIndex(
450 IN ULONG BlockCount, // number of items in array (pointed by List)
451 IN lba_t* List, // pointer to sorted (ASC) array of ULONGs
452 IN lba_t Lba // ULONG value to be searched for
453 )
454 {
455 if(!BlockCount)
456 return 0;
457
458 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
459
460 __asm push ecx
461 __asm push ebx
462 __asm push edx
463 __asm push esi
464 __asm push edi
465 // left = 0;
466 // right = BlockCount - 1;
467 // pos = 0;
468 __asm xor edx,edx // left
469 __asm mov ebx,BlockCount
470 __asm dec ebx // right
471 __asm xor esi,esi // pos
472 __asm mov edi,List // List
473 __asm mov ecx,Lba // Lba
474
475 While_1:
476 // while(left != right) {
477 __asm cmp edx,ebx
478 __asm jz EO_while_1
479
480 // pos = (left + right) >> 1;
481 __asm lea esi,[ebx+edx]
482 __asm shr esi,1
483 // if(List[pos] == Lba)
484 // return pos;
485 __asm mov eax,[edi+esi*4]
486 __asm cmp eax,ecx
487 __asm jz EO_while_2
488
489 // if(right - left == 1) {
490 __asm sub ebx,edx
491 __asm cmp ebx,1
492 __asm jne NO_r_sub_l_eq_1
493 // if(List[pos+1] < Lba) <=> if(List[pos+1] >= Lba)
494 // return (pos+2); <=> break;
495 // break; <=> return (pos+2);
496 __asm cmp [edi+esi*4+4],ecx
497 __asm jae EO_while_1
498 __asm add esi,2
499 __asm jmp EO_while_2
500 // }
501 NO_r_sub_l_eq_1:
502 // if(List[pos] < Lba) {
503 __asm cmp eax,ecx
504 __asm jae Update_r
505 // left = pos;
506 __asm add ebx,edx
507 __asm mov edx,esi
508 __asm jmp While_1
509 // } else {
510 Update_r:
511 // right = pos;
512 __asm mov ebx,esi
513 __asm jmp While_1
514 // }
515 // }
516 EO_while_1:
517 // if((List[pos] < Lba) && ((pos+1) <= BlockCount)) pos++;
518 __asm mov eax,[edi+esi*4]
519 __asm cmp eax,ecx
520 __asm jae EO_while_2
521 __asm inc esi
522 __asm cmp esi,BlockCount
523 __asm jbe EO_while_2
524 __asm dec esi
525 EO_while_2:
526 // return pos;
527 __asm mov eax,esi
528
529 __asm pop edi
530 __asm pop esi
531 __asm pop edx
532 __asm pop ebx
533 __asm pop ecx
534
535 #else // NO X86 optimization , use generic C/C++
536
537 ULONG pos;
538 ULONG left;
539 ULONG right;
540
541 if(!BlockCount)
542 return 0;
543
544 left = 0;
545 right = BlockCount - 1;
546 pos = 0;
547 while(left != right) {
548 pos = (left + right) >> 1;
549 if(List[pos] == Lba)
550 return pos;
551 if(right - left == 1) {
552 if(List[pos+1] < Lba)
553 return (pos+2);
554 break;
555 }
556 if(List[pos] < Lba) {
557 left = pos;
558 } else {
559 right = pos;
560 }
561 }
562 if((List[pos] < Lba) && ((pos+1) <= BlockCount)) pos++;
563
564 return pos;
565
566 #endif // _X86_
567
568 }
569
570 #ifdef _MSC_VER
571 #pragma warning(pop) // re-enable warning #4035
572 #endif
573
574 /*
575 WCacheInsertRangeToList() inserts values laying in range described
576 by Lba (1st value) and BCount (number of sequentially incremented
577 values) in sorted array of ULONGs pointed by List.
578 Ex.: (Lba, BCount)=(7,3) will insert values {7,8,9}.
579 If target array already contains one or more values falling in
580 requested range, they will be removed before insertion.
581 WCacheInsertRangeToList() updates value of (*BlockCount) to reflect
582 performed changes.
583 WCacheInsertRangeToList() assumes that target array is of enough size.
584 Internal routine
585 */
586 VOID
587 __fastcall
WCacheInsertRangeToList(IN lba_t * List,IN PULONG BlockCount,IN lba_t Lba,IN ULONG BCount)588 WCacheInsertRangeToList(
589 IN lba_t* List, // pointer to sorted (ASC) array of ULONGs
590 IN PULONG BlockCount, // pointer to number of items in array (pointed by List)
591 IN lba_t Lba, // initial value for insertion
592 IN ULONG BCount // number of sequentially incremented values to be inserted
593 )
594 {
595 if(!BCount)
596 return;
597
598 ASSERT(!(BCount & 0x80000000));
599
600 ULONG firstPos = WCacheGetSortedListIndex(*BlockCount, List, Lba);
601 ULONG lastPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+BCount);
602 ULONG offs = firstPos + BCount - lastPos;
603
604 if(offs) {
605 // move list tail
606 // ASSERT(lastPos+offs + ((*BlockCount) - lastPos) <= qq);
607 if(*BlockCount) {
608 #ifdef WCACHE_BOUND_CHECKS
609 MyCheckArray(List, lastPos+offs+(*BlockCount)-lastPos-1);
610 #endif //WCACHE_BOUND_CHECKS
611 DbgMoveMemory(&(List[lastPos+offs]), &(List[lastPos]), ((*BlockCount) - lastPos) * sizeof(ULONG));
612 }
613 lastPos += offs;
614 for(; firstPos<lastPos; firstPos++) {
615 #ifdef WCACHE_BOUND_CHECKS
616 MyCheckArray(List, firstPos);
617 #endif //WCACHE_BOUND_CHECKS
618 List[firstPos] = Lba;
619 Lba++;
620 }
621 (*BlockCount) += offs;
622 }
623 } // end WCacheInsertRangeToList()
624
625 /*
626 WCacheInsertItemToList() inserts value Lba in sorted array of
627 ULONGs pointed by List.
628 If target array already contains requested value, no
629 operations are performed.
630 WCacheInsertItemToList() updates value of (*BlockCount) to reflect
631 performed changes.
632 WCacheInsertItemToList() assumes that target array is of enough size.
633 Internal routine
634 */
635 VOID
636 __fastcall
WCacheInsertItemToList(IN lba_t * List,IN PULONG BlockCount,IN lba_t Lba)637 WCacheInsertItemToList(
638 IN lba_t* List, // pointer to sorted (ASC) array of lba_t's
639 IN PULONG BlockCount, // pointer to number of items in array (pointed by List)
640 IN lba_t Lba // value to be inserted
641 )
642 {
643 ULONG firstPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+1);
644 if(firstPos && (List[firstPos-1] == Lba))
645 return;
646
647 // move list tail
648 if(*BlockCount) {
649 #ifdef WCACHE_BOUND_CHECKS
650 MyCheckArray(List, firstPos+1+(*BlockCount)-firstPos-1);
651 #endif //WCACHE_BOUND_CHECKS
652 // DbgMoveMemory(&(List[firstPos+1]), &(List[firstPos]), ((*BlockCount) - firstPos)*sizeof(ULONG));
653 DbgMoveMemory(&(List[firstPos+1]), &(List[firstPos]), ((*BlockCount) - firstPos) * sizeof(ULONG));
654 }
655 #ifdef WCACHE_BOUND_CHECKS
656 MyCheckArray(List, firstPos);
657 #endif //WCACHE_BOUND_CHECKS
658 List[firstPos] = Lba;
659 (*BlockCount) ++;
660 } // end WCacheInsertItemToList()
661
662 /*
663 WCacheRemoveRangeFromList() removes values falling in range described
664 by Lba (1st value) and BCount (number of sequentially incremented
665 values) from sorted array of ULONGs pointed by List.
666 Ex.: (Lba, BCount)=(7,3) will remove values {7,8,9}.
667 If target array doesn't contain values falling in
668 requested range, no operation is performed.
669 WCacheRemoveRangeFromList() updates value of (*BlockCount) to reflect
670 performed changes.
671 Internal routine
672 */
673 VOID
674 __fastcall
WCacheRemoveRangeFromList(IN lba_t * List,IN PULONG BlockCount,IN lba_t Lba,IN ULONG BCount)675 WCacheRemoveRangeFromList(
676 IN lba_t* List, // pointer to sorted (ASC) array of ULONGs
677 IN PULONG BlockCount, // pointer to number of items in array (pointed by List)
678 IN lba_t Lba, // initial value for removal
679 IN ULONG BCount // number of sequentially incremented values to be removed
680 )
681 {
682 ULONG firstPos = WCacheGetSortedListIndex(*BlockCount, List, Lba);
683 ULONG lastPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+BCount);
684 ULONG offs = lastPos - firstPos;
685
686 if(offs) {
687 // move list tail
688 DbgMoveMemory(&(List[lastPos-offs]), &(List[lastPos]), ((*BlockCount) - lastPos) * sizeof(ULONG));
689 (*BlockCount) -= offs;
690 }
691 } // end WCacheRemoveRangeFromList()
692
693 /*
694 WCacheRemoveItemFromList() removes value Lba from sorted array
695 of ULONGs pointed by List.
696 If target array doesn't contain requested value, no
697 operations are performed.
698 WCacheRemoveItemFromList() updates value of (*BlockCount) to reflect
699 performed changes.
700 Internal routine
701 */
702 VOID
703 __fastcall
WCacheRemoveItemFromList(IN lba_t * List,IN PULONG BlockCount,IN lba_t Lba)704 WCacheRemoveItemFromList(
705 IN lba_t* List, // pointer to sorted (ASC) array of ULONGs
706 IN PULONG BlockCount, // pointer to number of items in array (pointed by List)
707 IN lba_t Lba // value to be removed
708 )
709 {
710 if(!(*BlockCount)) return;
711 ULONG lastPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+1);
712 if(!lastPos || (lastPos && (List[lastPos-1] != Lba)))
713 return;
714
715 // move list tail
716 DbgMoveMemory(&(List[lastPos-1]), &(List[lastPos]), ((*BlockCount) - lastPos) * sizeof(ULONG));
717 (*BlockCount) --;
718 } // end WCacheRemoveItemFromList()
719
720 /*
721 WCacheInitFrame() allocates storage for Frame (block_array)
722 with index 'frame', fills it with 0 (none of Blocks from
723 this Frame is cached) and inserts it's index to sorted array
724 of frame indexes.
725 WCacheInitFrame() also checks if number of frames reaches limit
726 and invokes WCacheCheckLimits() to free some Frames/Blocks
727 Internal routine
728 */
729 PW_CACHE_ENTRY
730 __fastcall
WCacheInitFrame(IN PW_CACHE Cache,IN PVOID Context,IN ULONG frame)731 WCacheInitFrame(
732 IN PW_CACHE Cache, // pointer to the Cache Control structure
733 IN PVOID Context, // caller's context (currently unused)
734 IN ULONG frame // frame index
735 )
736 {
737 PW_CACHE_ENTRY block_array;
738 ULONG l;
739 #ifdef DBG
740 ULONG old_count = Cache->FrameCount;
741 #endif //DBG
742
743 // We are about to add new cache frame.
744 // Thus check if we have enough free entries and
745 // flush unused ones if it is neccessary.
746 if(Cache->FrameCount >= Cache->MaxFrames) {
747 BrutePoint();
748 WCacheCheckLimits(Cache, Context, frame << Cache->BlocksPerFrameSh, Cache->PacketSize*2);
749 }
750 ASSERT(Cache->FrameCount < Cache->MaxFrames);
751 block_array = (PW_CACHE_ENTRY)MyAllocatePoolTag__(NonPagedPool, l = sizeof(W_CACHE_ENTRY) << Cache->BlocksPerFrameSh, MEM_WCFRM_TAG);
752 Cache->FrameList[frame].Frame = block_array;
753
754 // Keep history !!!
755 //Cache->FrameList[frame].UpdateCount = 0;
756 //Cache->FrameList[frame].AccessCount = 0;
757
758 if(block_array) {
759 ASSERT((ULONG_PTR)block_array > 0x1000);
760 WCacheInsertItemToList(Cache->CachedFramesList, &(Cache->FrameCount), frame);
761 RtlZeroMemory(block_array, l);
762 } else {
763 BrutePoint();
764 }
765 ASSERT(Cache->FrameCount <= Cache->MaxFrames);
766 #ifdef DBG
767 ASSERT(old_count < Cache->FrameCount);
768 #endif //DBG
769 return block_array;
770 } // end WCacheInitFrame()
771
772 /*
773 WCacheRemoveFrame() frees storage for Frame (block_array) with
774 index 'frame' and removes it's index from sorted array of
775 frame indexes.
776 Internal routine
777 */
778 VOID
779 __fastcall
WCacheRemoveFrame(IN PW_CACHE Cache,IN PVOID Context,IN ULONG frame)780 WCacheRemoveFrame(
781 IN PW_CACHE Cache, // pointer to the Cache Control structure
782 IN PVOID Context, // user's context (currently unused)
783 IN ULONG frame // frame index
784 )
785 {
786 PW_CACHE_ENTRY block_array;
787 #ifdef DBG
788 ULONG old_count = Cache->FrameCount;
789 #endif //DBG
790
791 ASSERT(Cache->FrameCount <= Cache->MaxFrames);
792 block_array = Cache->FrameList[frame].Frame;
793
794 WCacheRemoveItemFromList(Cache->CachedFramesList, &(Cache->FrameCount), frame);
795 MyFreePool__(block_array);
796 // ASSERT(!(Cache->FrameList[frame].WriteCount));
797 // ASSERT(!(Cache->FrameList[frame].WriteCount));
798 Cache->FrameList[frame].Frame = NULL;
799 ASSERT(Cache->FrameCount < Cache->MaxFrames);
800 #ifdef DBG
801 ASSERT(old_count > Cache->FrameCount);
802 #endif //DBG
803
804 } // end WCacheRemoveFrame()
805
806 /*
807 WCacheSetModFlag() sets Modified flag for Block with offset 'i'
808 in Frame 'block_array'
809 Internal routine
810 */
811 #define WCacheSetModFlag(block_array, i) \
812 *((PULONG)&(block_array[i].Sector)) |= WCACHE_FLAG_MODIFIED
813
814 /*
815 WCacheClrModFlag() clears Modified flag for Block with offset 'i'
816 in Frame 'block_array'
817 Internal routine
818 */
819 #define WCacheClrModFlag(block_array, i) \
820 *((PULONG)&(block_array[i].Sector)) &= ~WCACHE_FLAG_MODIFIED
821
822 /*
823 WCacheGetModFlag() returns non-zero value if Modified flag for
824 Block with offset 'i' in Frame 'block_array' is set. Otherwise
825 0 is returned.
826 Internal routine
827 */
828 #define WCacheGetModFlag(block_array, i) \
829 (*((PULONG)&(block_array[i].Sector)) & WCACHE_FLAG_MODIFIED)
830
831 #if 0
832 /*
833 WCacheSetBadFlag() sets Modified flag for Block with offset 'i'
834 in Frame 'block_array'
835 Internal routine
836 */
837 #define WCacheSetBadFlag(block_array, i) \
838 *((PULONG)&(block_array[i].Sector)) |= WCACHE_FLAG_BAD
839
840 /*
841 WCacheClrBadFlag() clears Modified flag for Block with offset 'i'
842 in Frame 'block_array'
843 Internal routine
844 */
845 #define WCacheClrBadFlag(block_array, i) \
846 *((PULONG)&(block_array[i].Sector)) &= ~WCACHE_FLAG_BAD
847
848 /*
849 WCacheGetBadFlag() returns non-zero value if Modified flag for
850 Block with offset 'i' in Frame 'block_array' is set. Otherwise
851 0 is returned.
852 Internal routine
853 */
854 #define WCacheGetBadFlag(block_array, i) \
855 (((UCHAR)(block_array[i].Sector)) & WCACHE_FLAG_BAD)
856 #endif //0
857
858 /*
859 WCacheSectorAddr() returns pointer to memory block containing cached
860 data for Block described by Frame (block_array) and offset in this
861 Frame (i). If requested Block is not cached yet NULL is returned.
862 Internal routine
863 */
864 #define WCacheSectorAddr(block_array, i) \
865 ((ULONG_PTR)(block_array[i].Sector) & WCACHE_ADDR_MASK)
866
867 /*
868 WCacheFreeSector() releases memory block containing cached
869 data for Block described by Frame (block_array) and offset in this
870 Frame (i). Should never be called for non-cached Blocks.
871 Internal routine
872 */
873 #define WCacheFreeSector(frame, offs) \
874 { \
875 DbgFreePool((PVOID)WCacheSectorAddr(block_array, offs)); \
876 block_array[offs].Sector = NULL; \
877 Cache->FrameList[frame].BlockCount--; \
878 }
879
880 /*
881 WCacheAllocAsyncEntry() allocates storage for async IO context,
882 links it to previously allocated async IO context (if any),
883 initializes synchronization (completion) event
884 and allocates temporary IO buffers.
885 Async IO contexts are used to create chained set of IO requests
886 durring top-level request precessing and wait for their completion.
887 Internal routine
888 */
889 PW_CACHE_ASYNC
WCacheAllocAsyncEntry(IN PW_CACHE Cache,IN OUT PW_CACHE_ASYNC * FirstWContext,IN OUT PW_CACHE_ASYNC * PrevWContext,IN ULONG BufferSize)890 WCacheAllocAsyncEntry(
891 IN PW_CACHE Cache, // pointer to the Cache Control structure
892 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to the pointer to
893 // the head of async IO context chain
894 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to the storage for pointer
895 // to newly allocated async IO context chain
896 IN ULONG BufferSize // requested IO buffer size
897 )
898 {
899 PW_CACHE_ASYNC WContext;
900 PCHAR Buffer;
901
902 WContext = (PW_CACHE_ASYNC)MyAllocatePoolTag__(NonPagedPool,sizeof(W_CACHE_ASYNC), MEM_WCCTX_TAG);
903 if(!WContext)
904 return NULL;
905 Buffer = (PCHAR)DbgAllocatePoolWithTag(NonPagedPool, BufferSize*(2-Cache->Chained), MEM_WCBUF_TAG);
906 if(!Buffer) {
907 MyFreePool__(WContext);
908 return NULL;
909 }
910
911 if(!Cache->Chained)
912 KeInitializeEvent(&(WContext->PhContext.event), SynchronizationEvent, FALSE);
913 WContext->Cache = Cache;
914 if(*PrevWContext)
915 (*PrevWContext)->NextWContext = WContext;
916 // WContext->NextWContext = (*PrevWContext);
917 WContext->NextWContext = NULL;
918 WContext->Buffer = Buffer;
919 WContext->Buffer2 = Buffer+(Cache->Chained ? 0 : BufferSize);
920
921 if(!(*FirstWContext))
922 (*FirstWContext) = WContext;
923 (*PrevWContext) = WContext;
924
925 return WContext;
926 } // end WCacheAllocAsyncEntry()
927
928 /*
929 WCacheFreeAsyncEntry() releases storage previously allocated for
930 async IO context.
931 Internal routine
932 */
933 VOID
WCacheFreeAsyncEntry(IN PW_CACHE Cache,PW_CACHE_ASYNC WContext)934 WCacheFreeAsyncEntry(
935 IN PW_CACHE Cache, // pointer to the Cache Control structure
936 PW_CACHE_ASYNC WContext // pointer to async IO context to release
937 )
938 {
939 DbgFreePool(WContext->Buffer);
940 MyFreePool__(WContext);
941 } // end WCacheFreeAsyncEntry()
942
943 //#define WCacheRaiseIoError(c, ct, s, l, bc, b, o, r)
944
945 OSSTATUS
WCacheRaiseIoError(IN PW_CACHE Cache,IN PVOID Context,IN OSSTATUS Status,IN ULONG Lba,IN ULONG BCount,IN PVOID Buffer,IN BOOLEAN ReadOp,IN PBOOLEAN Retry)946 WCacheRaiseIoError(
947 IN PW_CACHE Cache, // pointer to the Cache Control structure
948 IN PVOID Context,
949 IN OSSTATUS Status,
950 IN ULONG Lba,
951 IN ULONG BCount,
952 IN PVOID Buffer,
953 IN BOOLEAN ReadOp,
954 IN PBOOLEAN Retry
955 )
956 {
957 if(!Cache->ErrorHandlerProc)
958 return Status;
959
960 WCACHE_ERROR_CONTEXT ec;
961
962 ec.WCErrorCode = ReadOp ? WCACHE_ERROR_READ : WCACHE_ERROR_WRITE;
963 ec.Status = Status;
964 ec.ReadWrite.Lba = Lba;
965 ec.ReadWrite.BCount = BCount;
966 ec.ReadWrite.Buffer = Buffer;
967 Status = Cache->ErrorHandlerProc(Context, &ec);
968 if(Retry)
969 (*Retry) = ec.Retry;
970
971 return Status;
972
973 } // end WCacheRaiseIoError()
974
975 /*
976 WCacheUpdatePacket() attempts to updates packet containing target Block.
977 If async IO is enabled new IO context is added to the chain.
978 If packet containing target Block is modified and PrefereWrite flag
979 is NOT set, function returns with status STATUS_RETRY. This setting is
980 user in WCACHE_MODE_R mode to reduce physical writes on flush.
981 'State' parameter is used in async mode to determine the next processing
982 stege for given request
983 Internal routine
984 */
985 OSSTATUS
WCacheUpdatePacket(IN PW_CACHE Cache,IN PVOID Context,IN OUT PW_CACHE_ASYNC * FirstWContext,IN OUT PW_CACHE_ASYNC * PrevWContext,IN PW_CACHE_ENTRY block_array,IN lba_t firstLba,IN lba_t Lba,IN ULONG BSh,IN ULONG BS,IN ULONG PS,IN ULONG PSs,IN PSIZE_T ReadBytes,IN BOOLEAN PrefereWrite,IN ULONG State)986 WCacheUpdatePacket(
987 IN PW_CACHE Cache, // pointer to the Cache Control structure
988 IN PVOID Context, // user's context to be passed to user-supplied
989 // low-level IO routines (IO callbacks)
990 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context
991 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context
992 IN PW_CACHE_ENTRY block_array, // pointer to target Frame
993 IN lba_t firstLba, // LBA of the 1st block in target Frame
994 IN lba_t Lba, // LBA of target Block
995 IN ULONG BSh, // bit shift for Block size
996 IN ULONG BS, // Block size (bytes)
997 IN ULONG PS, // Packet size (bytes)
998 IN ULONG PSs, // Packet size (sectors)
999 IN PSIZE_T ReadBytes, // pointer to number of successfully read/written bytes
1000 IN BOOLEAN PrefereWrite, // allow physical write (flush) of modified packet
1001 IN ULONG State // callers state
1002 )
1003 {
1004 OSSTATUS status;
1005 PCHAR tmp_buff = Cache->tmp_buff;
1006 PCHAR tmp_buff2 = Cache->tmp_buff;
1007 BOOLEAN mod;
1008 BOOLEAN read;
1009 BOOLEAN zero;
1010 ULONG i;
1011 lba_t Lba0;
1012 PW_CACHE_ASYNC WContext;
1013 BOOLEAN Async = (Cache->ReadProcAsync && Cache->WriteProcAsync);
1014 ULONG block_type;
1015 BOOLEAN Chained = Cache->Chained;
1016
1017 // Check if we are going to write down to disk
1018 // all prewiously prepared (chained) data
1019 if(State == ASYNC_STATE_WRITE) {
1020 WContext = (*PrevWContext);
1021 tmp_buff = (PCHAR)(WContext->Buffer);
1022 tmp_buff2 = (PCHAR)(WContext->Buffer2);
1023 if(!Chained)
1024 mod = (DbgCompareMemory(tmp_buff2, tmp_buff, PS) != PS);
1025 goto try_write;
1026 }
1027
1028 // Check if packet contains modified blocks
1029 // If packet contains non-cached and unchanged, but used
1030 // blocks, it must be read from media before modification
1031 mod = read = zero = FALSE;
1032 Lba0 = Lba - firstLba;
1033 for(i=0; i<PSs; i++, Lba0++) {
1034 if(WCacheGetModFlag(block_array, Lba0)) {
1035 mod = TRUE;
1036 } else if(!WCacheSectorAddr(block_array,Lba0) &&
1037 ((block_type = Cache->CheckUsedProc(Context, Lba+i)) & WCACHE_BLOCK_USED) ) {
1038 //
1039 if(block_type & WCACHE_BLOCK_ZERO) {
1040 zero = TRUE;
1041 } else {
1042 read = TRUE;
1043 }
1044 }
1045 }
1046 // check if we are allowed to write to media
1047 if(mod && !PrefereWrite) {
1048 return STATUS_RETRY;
1049 }
1050 // return STATUS_SUCCESS if requested packet contains no modified blocks
1051 if(!mod) {
1052 (*ReadBytes) = PS;
1053 return STATUS_SUCCESS;
1054 }
1055
1056 // pefrorm full update cycle: prepare(optional)/read/modify/write
1057
1058 // do some preparations
1059 if(Chained || Async) {
1060 // For chained and async I/O we allocates context entry
1061 // and add it to list (chain)
1062 // We shall only read data to temporary buffer and
1063 // modify it. Write operations will be invoked later.
1064 // This is introduced in order to avoid frequent
1065 // read.write mode switching, because it significantly degrades
1066 // performance
1067 WContext = WCacheAllocAsyncEntry(Cache, FirstWContext, PrevWContext, PS);
1068 if(!WContext) {
1069 //return STATUS_INSUFFICIENT_RESOURCES;
1070 // try to recover
1071 Chained = FALSE;
1072 Async = FALSE;
1073 } else {
1074 tmp_buff = tmp_buff2 = (PCHAR)(WContext->Buffer);
1075 WContext->Lba = Lba;
1076 WContext->Cmd = ASYNC_CMD_UPDATE;
1077 WContext->State = ASYNC_STATE_NONE;
1078 }
1079 }
1080
1081 // read packet (if it necessary)
1082 if(read) {
1083 if(Async) {
1084 WContext->State = ASYNC_STATE_READ;
1085 status = Cache->ReadProcAsync(Context, WContext, tmp_buff, PS, Lba,
1086 &(WContext->TransferredBytes));
1087 // tmp_buff2 = (PCHAR)(WContext->Buffer2);
1088 (*ReadBytes) = PS;
1089 return status;
1090 } else {
1091 status = Cache->ReadProc(Context, tmp_buff, PS, Lba, ReadBytes, PH_TMP_BUFFER);
1092 }
1093 if(!OS_SUCCESS(status)) {
1094 status = WCacheRaiseIoError(Cache, Context, status, Lba, PSs, tmp_buff, WCACHE_R_OP, NULL);
1095 if(!OS_SUCCESS(status)) {
1096 return status;
1097 }
1098 }
1099 } else
1100 if(zero) {
1101 RtlZeroMemory(tmp_buff, PS);
1102 }
1103
1104 if(Chained) {
1105 // indicate that we prepared for writing block to disk
1106 WContext->State = ASYNC_STATE_WRITE_PRE;
1107 tmp_buff2 = tmp_buff;
1108 status = STATUS_SUCCESS;
1109 }
1110
1111 // modify packet
1112
1113 // If we didn't read packet from media, we can't
1114 // perform comparison to assure that packet was really modified.
1115 // Thus, assume that it is modified in this case.
1116 mod = !read || Cache->DoNotCompare;
1117 Lba0 = Lba - firstLba;
1118 for(i=0; i<PSs; i++, Lba0++) {
1119 if( WCacheGetModFlag(block_array, Lba0) ||
1120 (!read && WCacheSectorAddr(block_array,Lba0)) ) {
1121
1122 #ifdef _NTDEF_
1123 ASSERT((ULONG)WCacheSectorAddr(block_array,Lba0) & 0x80000000);
1124 #endif //_NTDEF_
1125 if(!mod) {
1126 ASSERT(read);
1127 mod = (DbgCompareMemory(tmp_buff2 + (i << BSh),
1128 (PVOID)WCacheSectorAddr(block_array, Lba0),
1129 BS) != BS);
1130 }
1131 if(mod) {
1132 DbgCopyMemory(tmp_buff2 + (i << BSh),
1133 (PVOID)WCacheSectorAddr(block_array, Lba0),
1134 BS);
1135 }
1136 }
1137 }
1138
1139 if(Chained &&
1140 WContext->State == ASYNC_STATE_WRITE_PRE) {
1141 // Return if block is prepared for write and we are in chained mode.
1142 if(!mod) {
1143 // Mark block as written if we have found that data in it
1144 // is not actually modified.
1145 WContext->State = ASYNC_STATE_DONE;
1146 (*ReadBytes) = PS;
1147 }
1148 return STATUS_SUCCESS;
1149 }
1150
1151 // write packet
1152
1153 // If the check above reported some changes in packet
1154 // we should write packet out to media.
1155 // Otherwise, just complete request.
1156 if(mod) {
1157 try_write:
1158 if(Async) {
1159 WContext->State = ASYNC_STATE_WRITE;
1160 status = Cache->WriteProcAsync(Context, WContext, tmp_buff2, PS, Lba,
1161 &(WContext->TransferredBytes), FALSE);
1162 (*ReadBytes) = PS;
1163 } else {
1164 status = Cache->WriteProc(Context, tmp_buff2, PS, Lba, ReadBytes, 0);
1165 if(!OS_SUCCESS(status)) {
1166 status = WCacheRaiseIoError(Cache, Context, status, Lba, PSs, tmp_buff2, WCACHE_W_OP, NULL);
1167 }
1168 }
1169 } else {
1170 if(Async)
1171 WCacheCompleteAsync__(WContext, STATUS_SUCCESS);
1172 (*ReadBytes) = PS;
1173 return STATUS_SUCCESS;
1174 }
1175
1176 return status;
1177 } // end WCacheUpdatePacket()
1178
1179 /*
1180 WCacheFreePacket() releases storage for all Blocks in packet.
1181 'frame' describes Frame, offset - Block in Frame. offset should be
1182 aligned on Packet size.
1183 Internal routine
1184 */
1185 VOID
WCacheFreePacket(IN PW_CACHE Cache,IN ULONG frame,IN PW_CACHE_ENTRY block_array,IN ULONG offs,IN ULONG PSs)1186 WCacheFreePacket(
1187 IN PW_CACHE Cache, // pointer to the Cache Control structure
1188 // IN PVOID Context,
1189 IN ULONG frame, // Frame index
1190 IN PW_CACHE_ENTRY block_array, // Frame
1191 IN ULONG offs, // offset in Frame
1192 IN ULONG PSs // Packet size (in Blocks)
1193 )
1194 {
1195 ULONG i;
1196 // mark as non-cached & free pool
1197 for(i=0; i<PSs; i++, offs++) {
1198 if(WCacheSectorAddr(block_array,offs)) {
1199 WCacheFreeSector(frame, offs);
1200 }
1201 }
1202 } // end WCacheFreePacket()
1203
1204 /*
1205 WCacheUpdatePacketComplete() is called to continue processing of packet
1206 being updated.
1207 In async mode it waits for completion of pre-read requests,
1208 initiates writes, waits for their completion and returns control to
1209 caller.
1210 Internal routine
1211 */
1212 VOID
WCacheUpdatePacketComplete(IN PW_CACHE Cache,IN PVOID Context,IN OUT PW_CACHE_ASYNC * FirstWContext,IN OUT PW_CACHE_ASYNC * PrevWContext,IN BOOLEAN FreePacket)1213 WCacheUpdatePacketComplete(
1214 IN PW_CACHE Cache, // pointer to the Cache Control structure
1215 IN PVOID Context, // user-supplied context for IO callbacks
1216 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context
1217 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context
1218 IN BOOLEAN FreePacket
1219 )
1220 {
1221 PW_CACHE_ASYNC WContext = (*FirstWContext);
1222 if(!WContext)
1223 return;
1224 PW_CACHE_ASYNC NextWContext;
1225 ULONG PS = Cache->BlockSize << Cache->PacketSizeSh; // packet size (bytes)
1226 ULONG PSs = Cache->PacketSize;
1227 ULONG frame;
1228 lba_t firstLba;
1229
1230 // Walk through all chained blocks and wait
1231 // for completion of read operations.
1232 // Also invoke writes of already prepared packets.
1233 while(WContext) {
1234 if(WContext->Cmd == ASYNC_CMD_UPDATE &&
1235 WContext->State == ASYNC_STATE_READ) {
1236 // wait for async read for update
1237 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL);
1238
1239 WContext->State = ASYNC_STATE_WRITE;
1240 WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1,
1241 PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE);
1242 } else
1243 if(WContext->Cmd == ASYNC_CMD_UPDATE &&
1244 WContext->State == ASYNC_STATE_WRITE_PRE) {
1245 // invoke physical write it the packet is prepared for writing
1246 // by previuous call to WCacheUpdatePacket()
1247 WContext->State = ASYNC_STATE_WRITE;
1248 WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1,
1249 PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE);
1250 WContext->State = ASYNC_STATE_DONE;
1251 } else
1252 if(WContext->Cmd == ASYNC_CMD_READ &&
1253 WContext->State == ASYNC_STATE_READ) {
1254 // wait for async read
1255 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL);
1256 }
1257 WContext = WContext->NextWContext;
1258 }
1259 // Walk through all chained blocks and wait
1260 // and wait for completion of async writes (if any).
1261 // Also free temporary buffers containing already written blocks.
1262 WContext = (*FirstWContext);
1263 while(WContext) {
1264 NextWContext = WContext->NextWContext;
1265 if(WContext->Cmd == ASYNC_CMD_UPDATE &&
1266 WContext->State == ASYNC_STATE_WRITE) {
1267
1268 if(!Cache->Chained)
1269 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL);
1270
1271 frame = WContext->Lba >> Cache->BlocksPerFrameSh;
1272 firstLba = frame << Cache->BlocksPerFrameSh;
1273
1274 if(FreePacket) {
1275 WCacheFreePacket(Cache, frame,
1276 Cache->FrameList[frame].Frame,
1277 WContext->Lba - firstLba, PSs);
1278 }
1279 }
1280 WCacheFreeAsyncEntry(Cache, WContext);
1281 WContext = NextWContext;
1282 }
1283 (*FirstWContext) = NULL;
1284 (*PrevWContext) = NULL;
1285 } // end WCacheUpdatePacketComplete()
1286
1287 /*
1288 WCacheCheckLimits() checks if we've enough free Frame- &
1289 Block-entries under Frame- and Block-limit to feet
1290 requested Blocks.
1291 If there is not enough entries, WCache initiates flush & purge
1292 process to satisfy request.
1293 This is dispatch routine, which calls
1294 WCacheCheckLimitsR() or WCacheCheckLimitsRW() depending on
1295 media type.
1296 Internal routine
1297 */
1298 OSSTATUS
1299 __fastcall
WCacheCheckLimits(IN PW_CACHE Cache,IN PVOID Context,IN lba_t ReqLba,IN ULONG BCount)1300 WCacheCheckLimits(
1301 IN PW_CACHE Cache, // pointer to the Cache Control structure
1302 IN PVOID Context, // user-supplied context for IO callbacks
1303 IN lba_t ReqLba, // first LBA to access/cache
1304 IN ULONG BCount // number of Blocks to access/cache
1305 )
1306 {
1307 /* if(!Cache->FrameCount || !Cache->BlockCount) {
1308 ASSERT(!Cache->FrameCount);
1309 ASSERT(!Cache->BlockCount);
1310 if(!Cache->FrameCount)
1311 return STATUS_SUCCESS;
1312 }*/
1313
1314 // check if we have reached Frame or Block limit
1315 if(!Cache->FrameCount && !Cache->BlockCount) {
1316 return STATUS_SUCCESS;
1317 }
1318
1319 // check for empty frames
1320 if(Cache->FrameCount > (Cache->MaxFrames*3)/4) {
1321 ULONG frame;
1322 ULONG i;
1323 for(i=Cache->FrameCount; i>0; i--) {
1324 frame = Cache->CachedFramesList[i-1];
1325 // check if frame is empty
1326 if(!(Cache->FrameList[frame].BlockCount)) {
1327 WCacheRemoveFrame(Cache, Context, frame);
1328 } else {
1329 ASSERT(Cache->FrameList[frame].Frame);
1330 }
1331 }
1332 }
1333
1334 if(!Cache->BlockCount) {
1335 return STATUS_SUCCESS;
1336 }
1337
1338 // invoke media-specific limit-checker
1339 switch(Cache->Mode) {
1340 case WCACHE_MODE_RAM:
1341 return WCacheCheckLimitsRAM(Cache, Context, ReqLba, BCount);
1342 case WCACHE_MODE_ROM:
1343 case WCACHE_MODE_RW:
1344 return WCacheCheckLimitsRW(Cache, Context, ReqLba, BCount);
1345 case WCACHE_MODE_R:
1346 return WCacheCheckLimitsR(Cache, Context, ReqLba, BCount);
1347 }
1348 return STATUS_DRIVER_INTERNAL_ERROR;
1349 } // end WCacheCheckLimits()
1350
1351 /*
1352 WCacheCheckLimitsRW() implements automatic flush and purge of
1353 unused blocks to keep enough free cache entries for newly
1354 read/written blocks for Random Access and ReWritable media
1355 using Read/Modify/Write technology.
1356 See also WCacheCheckLimits()
1357 Internal routine
1358 */
1359 OSSTATUS
1360 __fastcall
WCacheCheckLimitsRW(IN PW_CACHE Cache,IN PVOID Context,IN lba_t ReqLba,IN ULONG BCount)1361 WCacheCheckLimitsRW(
1362 IN PW_CACHE Cache, // pointer to the Cache Control structure
1363 IN PVOID Context, // user-supplied context for IO callbacks
1364 IN lba_t ReqLba, // first LBA to access/cache
1365 IN ULONG BCount // number of Blocks to access/cache
1366 )
1367 {
1368 ULONG frame;
1369 lba_t firstLba;
1370 lba_t* List = Cache->CachedBlocksList;
1371 lba_t lastLba;
1372 lba_t Lba;
1373 // PCHAR tmp_buff = Cache->tmp_buff;
1374 ULONG firstPos;
1375 ULONG lastPos;
1376 ULONG BSh = Cache->BlockSizeSh;
1377 ULONG BS = Cache->BlockSize;
1378 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
1379 ULONG PSs = Cache->PacketSize;
1380 ULONG try_count = 0;
1381 PW_CACHE_ENTRY block_array;
1382 OSSTATUS status;
1383 SIZE_T ReadBytes;
1384 ULONG FreeFrameCount = 0;
1385 // PVOID addr;
1386 PW_CACHE_ASYNC FirstWContext = NULL;
1387 PW_CACHE_ASYNC PrevWContext = NULL;
1388 ULONG chain_count = 0;
1389
1390 if(Cache->FrameCount >= Cache->MaxFrames) {
1391 FreeFrameCount = Cache->FramesToKeepFree;
1392 } else
1393 if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
1394 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) {
1395 // we need free space to grow WCache without flushing data
1396 // for some period of time
1397 FreeFrameCount = Cache->FramesToKeepFree;
1398 goto Try_Another_Frame;
1399 }
1400 // remove(flush) some frames
1401 while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) {
1402 Try_Another_Frame:
1403 if(!Cache->FrameCount || !Cache->BlockCount) {
1404 //ASSERT(!Cache->FrameCount);
1405 if(Cache->FrameCount) {
1406 UDFPrint(("ASSERT: Cache->FrameCount = %d, when 0 is expected\n", Cache->FrameCount));
1407 }
1408 ASSERT(!Cache->BlockCount);
1409 if(!Cache->FrameCount)
1410 break;
1411 }
1412
1413 frame = WCacheFindFrameToRelease(Cache);
1414 #if 0
1415 if(Cache->FrameList[frame].WriteCount) {
1416 try_count++;
1417 if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame;
1418 } else {
1419 try_count = 0;
1420 }
1421 #else
1422 if(Cache->FrameList[frame].UpdateCount) {
1423 try_count = MAX_TRIES_FOR_NA;
1424 } else {
1425 try_count = 0;
1426 }
1427 #endif
1428
1429 if(FreeFrameCount)
1430 FreeFrameCount--;
1431
1432 firstLba = frame << Cache->BlocksPerFrameSh;
1433 lastLba = firstLba + Cache->BlocksPerFrame;
1434 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba);
1435 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba);
1436 block_array = Cache->FrameList[frame].Frame;
1437
1438 if(!block_array) {
1439 UDFPrint(("Hmm...\n"));
1440 BrutePoint();
1441 return STATUS_DRIVER_INTERNAL_ERROR;
1442 }
1443
1444 while(firstPos < lastPos) {
1445 // flush packet
1446 Lba = List[firstPos] & ~(PSs-1);
1447
1448 // write packet out or prepare and add to chain (if chained mode enabled)
1449 status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
1450 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE);
1451
1452 if(status != STATUS_PENDING) {
1453 // free memory
1454 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs);
1455 }
1456
1457 Lba += PSs;
1458 while((firstPos < lastPos) && (Lba > List[firstPos])) {
1459 firstPos++;
1460 }
1461 chain_count++;
1462 // write chained packets
1463 if(chain_count >= WCACHE_MAX_CHAIN) {
1464 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
1465 chain_count = 0;
1466 }
1467 }
1468 // remove flushed blocks from all lists
1469 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame);
1470 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame);
1471
1472 WCacheRemoveFrame(Cache, Context, frame);
1473 }
1474
1475 // check if we try to read too much data
1476 if(BCount > Cache->MaxBlocks) {
1477 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext);
1478 return STATUS_INVALID_PARAMETER;
1479 }
1480
1481 // remove(flush) packet
1482 while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
1483 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) {
1484 try_count = 0;
1485 Try_Another_Block:
1486
1487 Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1);
1488 if(Lba == WCACHE_INVALID_LBA) {
1489 ASSERT(!Cache->FrameCount);
1490 ASSERT(!Cache->BlockCount);
1491 break;
1492 }
1493 frame = Lba >> Cache->BlocksPerFrameSh;
1494 firstLba = frame << Cache->BlocksPerFrameSh;
1495 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba);
1496 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs);
1497 block_array = Cache->FrameList[frame].Frame;
1498 if(!block_array) {
1499 // write already prepared blocks to disk and return error
1500 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext);
1501 ASSERT(FALSE);
1502 return STATUS_DRIVER_INTERNAL_ERROR;
1503 }
1504
1505 // write packet out or prepare and add to chain (if chained mode enabled)
1506 status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
1507 Lba, BSh, BS, PS, PSs, &ReadBytes, (try_count >= MAX_TRIES_FOR_NA), ASYNC_STATE_NONE);
1508
1509 if(status == STATUS_RETRY) {
1510 try_count++;
1511 goto Try_Another_Block;
1512 }
1513
1514 // free memory
1515 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs);
1516
1517 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs);
1518 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs);
1519 // check if frame is empty
1520 if(!(Cache->FrameList[frame].BlockCount)) {
1521 WCacheRemoveFrame(Cache, Context, frame);
1522 } else {
1523 ASSERT(Cache->FrameList[frame].Frame);
1524 }
1525 chain_count++;
1526 if(chain_count >= WCACHE_MAX_CHAIN) {
1527 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
1528 chain_count = 0;
1529 }
1530 }
1531 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext);
1532 return STATUS_SUCCESS;
1533 } // end WCacheCheckLimitsRW()
1534
1535 OSSTATUS
1536 __fastcall
WCacheFlushBlocksRAM(IN PW_CACHE Cache,IN PVOID Context,PW_CACHE_ENTRY block_array,lba_t * List,ULONG firstPos,ULONG lastPos,BOOLEAN Purge)1537 WCacheFlushBlocksRAM(
1538 IN PW_CACHE Cache, // pointer to the Cache Control structure
1539 IN PVOID Context, // user-supplied context for IO callbacks
1540 PW_CACHE_ENTRY block_array,
1541 lba_t* List,
1542 ULONG firstPos,
1543 ULONG lastPos,
1544 BOOLEAN Purge
1545 )
1546 {
1547 ULONG frame;
1548 lba_t Lba;
1549 lba_t PrevLba;
1550 lba_t firstLba;
1551 PCHAR tmp_buff = NULL;
1552 ULONG n;
1553 ULONG BSh = Cache->BlockSizeSh;
1554 ULONG BS = Cache->BlockSize;
1555 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
1556 ULONG PSs = Cache->PacketSize;
1557 SIZE_T _WrittenBytes;
1558 OSSTATUS status = STATUS_SUCCESS;
1559
1560 frame = List[firstPos] >> Cache->BlocksPerFrameSh;
1561 firstLba = frame << Cache->BlocksPerFrameSh;
1562
1563 while(firstPos < lastPos) {
1564 // flush blocks
1565 ASSERT(Cache->FrameCount <= Cache->MaxFrames);
1566 Lba = List[firstPos];
1567 if(!WCacheGetModFlag(block_array, Lba - firstLba)) {
1568 // free memory
1569 if(Purge) {
1570 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, 1);
1571 }
1572 firstPos++;
1573 continue;
1574 }
1575 tmp_buff = Cache->tmp_buff;
1576 PrevLba = Lba;
1577 n=1;
1578 while((firstPos+n < lastPos) &&
1579 (List[firstPos+n] == PrevLba+1)) {
1580 PrevLba++;
1581 if(!WCacheGetModFlag(block_array, PrevLba - firstLba))
1582 break;
1583 DbgCopyMemory(tmp_buff + (n << BSh),
1584 (PVOID)WCacheSectorAddr(block_array, PrevLba - firstLba),
1585 BS);
1586 n++;
1587 if(n >= PSs)
1588 break;
1589 }
1590 if(n > 1) {
1591 DbgCopyMemory(tmp_buff,
1592 (PVOID)WCacheSectorAddr(block_array, Lba - firstLba),
1593 BS);
1594 } else {
1595 tmp_buff = (PCHAR)WCacheSectorAddr(block_array, Lba - firstLba);
1596 }
1597 // write sectors out
1598 status = Cache->WriteProc(Context, tmp_buff, n<<BSh, Lba, &_WrittenBytes, 0);
1599 if(!OS_SUCCESS(status)) {
1600 status = WCacheRaiseIoError(Cache, Context, status, Lba, n, tmp_buff, WCACHE_W_OP, NULL);
1601 if(!OS_SUCCESS(status)) {
1602 BrutePoint();
1603 }
1604 }
1605 firstPos += n;
1606 if(Purge) {
1607 // free memory
1608 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, n);
1609 } else {
1610 // clear Modified flag
1611 ULONG i;
1612 Lba -= firstLba;
1613 for(i=0; i<n; i++) {
1614 WCacheClrModFlag(block_array, Lba+i);
1615 }
1616 }
1617 }
1618
1619 return status;
1620 } // end WCacheFlushBlocksRAM()
1621
1622 /*
1623 WCacheCheckLimitsRAM() implements automatic flush and purge of
1624 unused blocks to keep enough free cache entries for newly
1625 read/written blocks for Random Access media.
1626 See also WCacheCheckLimits()
1627 Internal routine
1628 */
1629 OSSTATUS
1630 __fastcall
WCacheCheckLimitsRAM(IN PW_CACHE Cache,IN PVOID Context,IN lba_t ReqLba,IN ULONG BCount)1631 WCacheCheckLimitsRAM(
1632 IN PW_CACHE Cache, // pointer to the Cache Control structure
1633 IN PVOID Context, // user-supplied context for IO callbacks
1634 IN lba_t ReqLba, // first LBA to access/cache
1635 IN ULONG BCount // number of Blocks to access/cache
1636 )
1637 {
1638 ULONG frame;
1639 lba_t firstLba;
1640 lba_t* List = Cache->CachedBlocksList;
1641 lba_t lastLba;
1642 lba_t Lba;
1643 // PCHAR tmp_buff = Cache->tmp_buff;
1644 ULONG firstPos;
1645 ULONG lastPos;
1646 // ULONG BSh = Cache->BlockSizeSh;
1647 // ULONG BS = Cache->BlockSize;
1648 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
1649 ULONG PSs = Cache->PacketSize;
1650 // ULONG try_count = 0;
1651 PW_CACHE_ENTRY block_array;
1652 // OSSTATUS status;
1653 ULONG FreeFrameCount = 0;
1654 // PVOID addr;
1655
1656 if(Cache->FrameCount >= Cache->MaxFrames) {
1657 FreeFrameCount = Cache->FramesToKeepFree;
1658 } else
1659 if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
1660 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) {
1661 // we need free space to grow WCache without flushing data
1662 // for some period of time
1663 FreeFrameCount = Cache->FramesToKeepFree;
1664 goto Try_Another_Frame;
1665 }
1666 // remove(flush) some frames
1667 while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) {
1668 ASSERT(Cache->FrameCount <= Cache->MaxFrames);
1669 Try_Another_Frame:
1670 if(!Cache->FrameCount || !Cache->BlockCount) {
1671 ASSERT(!Cache->FrameCount);
1672 ASSERT(!Cache->BlockCount);
1673 if(!Cache->FrameCount)
1674 break;
1675 }
1676
1677 frame = WCacheFindFrameToRelease(Cache);
1678 #if 0
1679 if(Cache->FrameList[frame].WriteCount) {
1680 try_count++;
1681 if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame;
1682 } else {
1683 try_count = 0;
1684 }
1685 #else
1686 /*
1687 if(Cache->FrameList[frame].UpdateCount) {
1688 try_count = MAX_TRIES_FOR_NA;
1689 } else {
1690 try_count = 0;
1691 }
1692 */
1693 #endif
1694
1695 if(FreeFrameCount)
1696 FreeFrameCount--;
1697
1698 firstLba = frame << Cache->BlocksPerFrameSh;
1699 lastLba = firstLba + Cache->BlocksPerFrame;
1700 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba);
1701 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba);
1702 block_array = Cache->FrameList[frame].Frame;
1703
1704 if(!block_array) {
1705 UDFPrint(("Hmm...\n"));
1706 BrutePoint();
1707 return STATUS_DRIVER_INTERNAL_ERROR;
1708 }
1709 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE);
1710
1711 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame);
1712 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame);
1713 WCacheRemoveFrame(Cache, Context, frame);
1714 }
1715
1716 // check if we try to read too much data
1717 if(BCount > Cache->MaxBlocks) {
1718 return STATUS_INVALID_PARAMETER;
1719 }
1720
1721 // remove(flush) packet
1722 while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
1723 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) {
1724 // try_count = 0;
1725 //Try_Another_Block:
1726
1727 ASSERT(Cache->FrameCount <= Cache->MaxFrames);
1728 Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1);
1729 if(Lba == WCACHE_INVALID_LBA) {
1730 ASSERT(!Cache->FrameCount);
1731 ASSERT(!Cache->BlockCount);
1732 break;
1733 }
1734 frame = Lba >> Cache->BlocksPerFrameSh;
1735 firstLba = frame << Cache->BlocksPerFrameSh;
1736 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba);
1737 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs);
1738 block_array = Cache->FrameList[frame].Frame;
1739 if(!block_array) {
1740 ASSERT(FALSE);
1741 return STATUS_DRIVER_INTERNAL_ERROR;
1742 }
1743 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE);
1744 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs);
1745 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs);
1746 // check if frame is empty
1747 if(!(Cache->FrameList[frame].BlockCount)) {
1748 WCacheRemoveFrame(Cache, Context, frame);
1749 } else {
1750 ASSERT(Cache->FrameList[frame].Frame);
1751 }
1752 }
1753 return STATUS_SUCCESS;
1754 } // end WCacheCheckLimitsRAM()
1755
1756 /*
1757 WCachePurgeAllRAM()
1758 Internal routine
1759 */
1760 OSSTATUS
1761 __fastcall
WCachePurgeAllRAM(IN PW_CACHE Cache,IN PVOID Context)1762 WCachePurgeAllRAM(
1763 IN PW_CACHE Cache, // pointer to the Cache Control structure
1764 IN PVOID Context // user-supplied context for IO callbacks
1765 )
1766 {
1767 ULONG frame;
1768 lba_t firstLba;
1769 lba_t* List = Cache->CachedBlocksList;
1770 lba_t lastLba;
1771 ULONG firstPos;
1772 ULONG lastPos;
1773 PW_CACHE_ENTRY block_array;
1774 // OSSTATUS status;
1775
1776 // remove(flush) some frames
1777 while(Cache->FrameCount) {
1778
1779 frame = Cache->CachedFramesList[0];
1780
1781 firstLba = frame << Cache->BlocksPerFrameSh;
1782 lastLba = firstLba + Cache->BlocksPerFrame;
1783 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba);
1784 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba);
1785 block_array = Cache->FrameList[frame].Frame;
1786
1787 if(!block_array) {
1788 UDFPrint(("Hmm...\n"));
1789 BrutePoint();
1790 return STATUS_DRIVER_INTERNAL_ERROR;
1791 }
1792 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE);
1793
1794 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame);
1795 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame);
1796 WCacheRemoveFrame(Cache, Context, frame);
1797 }
1798
1799 ASSERT(!Cache->FrameCount);
1800 ASSERT(!Cache->BlockCount);
1801 return STATUS_SUCCESS;
1802 } // end WCachePurgeAllRAM()
1803
1804 /*
1805 WCacheFlushAllRAM()
1806 Internal routine
1807 */
1808 OSSTATUS
1809 __fastcall
WCacheFlushAllRAM(IN PW_CACHE Cache,IN PVOID Context)1810 WCacheFlushAllRAM(
1811 IN PW_CACHE Cache, // pointer to the Cache Control structure
1812 IN PVOID Context // user-supplied context for IO callbacks
1813 )
1814 {
1815 ULONG frame;
1816 lba_t firstLba;
1817 lba_t* List = Cache->CachedBlocksList;
1818 lba_t lastLba;
1819 ULONG firstPos;
1820 ULONG lastPos;
1821 PW_CACHE_ENTRY block_array;
1822 // OSSTATUS status;
1823
1824 // flush frames
1825 while(Cache->WriteCount) {
1826
1827 frame = Cache->CachedModifiedBlocksList[0] >> Cache->BlocksPerFrameSh;
1828
1829 firstLba = frame << Cache->BlocksPerFrameSh;
1830 lastLba = firstLba + Cache->BlocksPerFrame;
1831 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba);
1832 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba);
1833 block_array = Cache->FrameList[frame].Frame;
1834
1835 if(!block_array) {
1836 UDFPrint(("Hmm...\n"));
1837 BrutePoint();
1838 return STATUS_DRIVER_INTERNAL_ERROR;
1839 }
1840 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, FALSE);
1841
1842 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame);
1843 }
1844
1845 return STATUS_SUCCESS;
1846 } // end WCacheFlushAllRAM()
1847
1848 /*
1849 WCachePreReadPacket__() reads & caches the whole packet containing
1850 requested LBA. This routine just caches data, it doesn't copy anything
1851 to user buffer.
1852 In general we have no user buffer here... ;)
1853 Public routine
1854 */
1855 OSSTATUS
WCachePreReadPacket__(IN PW_CACHE Cache,IN PVOID Context,IN lba_t Lba)1856 WCachePreReadPacket__(
1857 IN PW_CACHE Cache, // pointer to the Cache Control structure
1858 IN PVOID Context, // user-supplied context for IO callbacks
1859 IN lba_t Lba // LBA to cache together with whole packet
1860 )
1861 {
1862 ULONG frame;
1863 OSSTATUS status = STATUS_SUCCESS;
1864 PW_CACHE_ENTRY block_array;
1865 ULONG BSh = Cache->BlockSizeSh;
1866 ULONG BS = Cache->BlockSize;
1867 PCHAR addr;
1868 SIZE_T _ReadBytes;
1869 ULONG PS = Cache->PacketSize; // (in blocks)
1870 ULONG BCount = PS;
1871 ULONG i, n, err_count;
1872 BOOLEAN sector_added = FALSE;
1873 ULONG block_type;
1874 BOOLEAN zero = FALSE;//TRUE;
1875 /*
1876 ULONG first_zero=0, last_zero=0;
1877 BOOLEAN count_first_zero = TRUE;
1878 */
1879
1880 Lba &= ~(PS-1);
1881 frame = Lba >> Cache->BlocksPerFrameSh;
1882 i = Lba - (frame << Cache->BlocksPerFrameSh);
1883
1884 // assume successful operation
1885 block_array = Cache->FrameList[frame].Frame;
1886 if(!block_array) {
1887 ASSERT(Cache->FrameCount < Cache->MaxFrames);
1888 block_array = WCacheInitFrame(Cache, Context, frame);
1889 if(!block_array)
1890 return STATUS_INSUFFICIENT_RESOURCES;
1891 }
1892
1893 // skip cached extent (if any)
1894 n=0;
1895 while((n < BCount) &&
1896 (n < Cache->BlocksPerFrame)) {
1897
1898 addr = (PCHAR)WCacheSectorAddr(block_array, i+n);
1899 block_type = Cache->CheckUsedProc(Context, Lba+n);
1900 if(/*WCacheGetBadFlag(block_array,i+n)*/
1901 block_type & WCACHE_BLOCK_BAD) {
1902 // bad packet. no pre-read
1903 return STATUS_DEVICE_DATA_ERROR;
1904 }
1905 if(!(block_type & WCACHE_BLOCK_ZERO)) {
1906 zero = FALSE;
1907 //count_first_zero = FALSE;
1908 //last_zero = 0;
1909 if(!addr) {
1910 // sector is not cached, stop search
1911 break;
1912 }
1913 } else {
1914 /*
1915 if(count_first_zero) {
1916 first_zero++;
1917 }
1918 last_zero++;
1919 */
1920 }
1921 n++;
1922 }
1923 // do nothing if all sectors are already cached
1924 if(n < BCount) {
1925
1926 // read whole packet
1927 if(!zero) {
1928 status = Cache->ReadProc(Context, Cache->tmp_buff_r, PS<<BSh, Lba, &_ReadBytes, PH_TMP_BUFFER);
1929 if(!OS_SUCCESS(status)) {
1930 status = WCacheRaiseIoError(Cache, Context, status, Lba, PS, Cache->tmp_buff_r, WCACHE_R_OP, NULL);
1931 }
1932 } else {
1933 status = STATUS_SUCCESS;
1934 //RtlZeroMemory(Cache->tmp_buff_r, PS<<BSh);
1935 _ReadBytes = PS<<BSh;
1936 }
1937 if(OS_SUCCESS(status)) {
1938 // and now we'll copy them to cache
1939 for(n=0; n<BCount; n++, i++) {
1940 if(WCacheSectorAddr(block_array,i)) {
1941 continue;
1942 }
1943 addr = block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
1944 if(!addr) {
1945 BrutePoint();
1946 break;
1947 }
1948 sector_added = TRUE;
1949 if(!zero) {
1950 DbgCopyMemory(addr, Cache->tmp_buff_r+(n<<BSh), BS);
1951 } else {
1952 RtlZeroMemory(addr, BS);
1953 }
1954 Cache->FrameList[frame].BlockCount++;
1955 }
1956 } else {
1957 // read sectors one by one and copy them to cache
1958 // unreadable sectors will be treated as zero-filled
1959 err_count = 0;
1960 for(n=0; n<BCount; n++, i++) {
1961 if(WCacheSectorAddr(block_array,i)) {
1962 continue;
1963 }
1964 addr = block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
1965 if(!addr) {
1966 BrutePoint();
1967 break;
1968 }
1969 sector_added = TRUE;
1970 status = Cache->ReadProc(Context, Cache->tmp_buff_r, BS, Lba+n, &_ReadBytes, PH_TMP_BUFFER);
1971 if(!OS_SUCCESS(status)) {
1972 status = WCacheRaiseIoError(Cache, Context, status, Lba+n, 1, Cache->tmp_buff_r, WCACHE_R_OP, NULL);
1973 if(!OS_SUCCESS(status)) {
1974 err_count++;
1975 }
1976 }
1977 if(!zero && OS_SUCCESS(status)) {
1978 DbgCopyMemory(addr, Cache->tmp_buff_r, BS);
1979 } else
1980 if(Cache->RememberBB) {
1981 RtlZeroMemory(addr, BS);
1982 /*
1983 if(!OS_SUCCESS(status)) {
1984 WCacheSetBadFlag(block_array,i);
1985 }
1986 */
1987 }
1988 Cache->FrameList[frame].BlockCount++;
1989 if(err_count >= 2) {
1990 break;
1991 }
1992 }
1993 // _ReadBytes = n<<BSh;
1994 }
1995 }
1996
1997 // we know the number of unread sectors if an error occured
1998 // so we can need to update BlockCount
1999 // return number of read bytes
2000 if(sector_added)
2001 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, n);
2002
2003 return status;
2004 } // end WCachePreReadPacket__()
2005
2006 /*
2007 WCacheReadBlocks__() reads data from cache or
2008 read it form media and store in cache.
2009 Public routine
2010 */
2011 OSSTATUS
WCacheReadBlocks__(IN PW_CACHE Cache,IN PVOID Context,IN PCHAR Buffer,IN lba_t Lba,IN ULONG BCount,OUT PSIZE_T ReadBytes,IN BOOLEAN CachedOnly)2012 WCacheReadBlocks__(
2013 IN PW_CACHE Cache, // pointer to the Cache Control structure
2014 IN PVOID Context, // user-supplied context for IO callbacks
2015 IN PCHAR Buffer, // user-supplied buffer for read blocks
2016 IN lba_t Lba, // LBA to start read from
2017 IN ULONG BCount, // number of blocks to be read
2018 OUT PSIZE_T ReadBytes, // user-supplied pointer to ULONG that will
2019 // recieve number of actually read bytes
2020 IN BOOLEAN CachedOnly // specifies that cache is already locked
2021 )
2022 {
2023 ULONG frame;
2024 ULONG i, saved_i, saved_BC = BCount, n;
2025 OSSTATUS status = STATUS_SUCCESS;
2026 PW_CACHE_ENTRY block_array;
2027 ULONG BSh = Cache->BlockSizeSh;
2028 SIZE_T BS = Cache->BlockSize;
2029 PCHAR addr;
2030 ULONG to_read, saved_to_read;
2031 // PCHAR saved_buff = Buffer;
2032 SIZE_T _ReadBytes;
2033 ULONG PS = Cache->PacketSize;
2034 ULONG MaxR = Cache->MaxBytesToRead;
2035 ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n
2036 ULONG d;
2037 ULONG block_type;
2038
2039 WcPrint(("WC:R %x (%x)\n", Lba, BCount));
2040
2041 (*ReadBytes) = 0;
2042 // check if we try to read too much data
2043 if(BCount >= Cache->MaxBlocks) {
2044 i = 0;
2045 if(CachedOnly) {
2046 status = STATUS_INVALID_PARAMETER;
2047 goto EO_WCache_R2;
2048 }
2049 while(TRUE) {
2050 status = WCacheReadBlocks__(Cache, Context, Buffer + (i<<BSh), Lba, PS, &_ReadBytes, FALSE);
2051 (*ReadBytes) += _ReadBytes;
2052 if(!OS_SUCCESS(status) || (BCount <= PS)) break;
2053 BCount -= PS;
2054 Lba += PS;
2055 i += PS;
2056 }
2057 return status;
2058 }
2059 // check if we try to access beyond cached area
2060 if((Lba < Cache->FirstLba) ||
2061 (Lba + BCount - 1 > Cache->LastLba)) {
2062 status = Cache->ReadProc(Context, Buffer, BCount, Lba, ReadBytes, 0);
2063 if(!OS_SUCCESS(status)) {
2064 status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_R_OP, NULL);
2065 }
2066 return status;
2067 }
2068 if(!CachedOnly) {
2069 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2070 }
2071
2072 frame = Lba >> Cache->BlocksPerFrameSh;
2073 i = Lba - (frame << Cache->BlocksPerFrameSh);
2074
2075 if(Cache->CacheWholePacket && (BCount < PS)) {
2076 if(!CachedOnly &&
2077 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba & ~(PS-1), PS*2)) ) {
2078 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2079 return status;
2080 }
2081 } else {
2082 if(!CachedOnly &&
2083 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) {
2084 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2085 return status;
2086 }
2087 }
2088 if(!CachedOnly) {
2089 // convert to shared
2090 // ExConvertExclusiveToSharedLite(&(Cache->WCacheLock));
2091 }
2092
2093 // pre-read packet. It is very useful for
2094 // highly fragmented files
2095 if(Cache->CacheWholePacket && (BCount < PS)) {
2096 // status = WCacheReadBlocks__(Cache, Context, Cache->tmp_buff_r, Lba & (~PacketMask), PS, &_ReadBytes, TRUE);
2097 // we should not perform IO if user requested CachedOnly data
2098 if(!CachedOnly) {
2099 status = WCachePreReadPacket__(Cache, Context, Lba);
2100 }
2101 status = STATUS_SUCCESS;
2102 }
2103
2104 // assume successful operation
2105 block_array = Cache->FrameList[frame].Frame;
2106 if(!block_array) {
2107 ASSERT(!CachedOnly);
2108 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2109 block_array = WCacheInitFrame(Cache, Context, frame);
2110 if(!block_array) {
2111 status = STATUS_INSUFFICIENT_RESOURCES;
2112 goto EO_WCache_R;
2113 }
2114 }
2115
2116 Cache->FrameList[frame].AccessCount++;
2117 while(BCount) {
2118 if(i >= Cache->BlocksPerFrame) {
2119 frame++;
2120 block_array = Cache->FrameList[frame].Frame;
2121 i -= Cache->BlocksPerFrame;
2122 }
2123 if(!block_array) {
2124 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2125 block_array = WCacheInitFrame(Cache, Context, frame);
2126 if(!block_array) {
2127 status = STATUS_INSUFFICIENT_RESOURCES;
2128 goto EO_WCache_R;
2129 }
2130 }
2131 // 'read' cached extent (if any)
2132 // it is just copying
2133 while(BCount &&
2134 (i < Cache->BlocksPerFrame) &&
2135 (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) {
2136 block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount);
2137 if(block_type & WCACHE_BLOCK_BAD) {
2138 //if(WCacheGetBadFlag(block_array,i)) {
2139 status = STATUS_DEVICE_DATA_ERROR;
2140 goto EO_WCache_R;
2141 }
2142 DbgCopyMemory(Buffer, addr, BS);
2143 Buffer += BS;
2144 *ReadBytes += BS;
2145 i++;
2146 BCount--;
2147 }
2148 // read non-cached packet-size-aligned extent (if any)
2149 // now we'll calculate total length & decide if it has enough size
2150 if(!((d = Lba+saved_BC-BCount) & PacketMask) && d ) {
2151 n = 0;
2152 while(BCount &&
2153 (i < Cache->BlocksPerFrame) &&
2154 (!WCacheSectorAddr(block_array, i)) ) {
2155 n++;
2156 BCount--;
2157 }
2158 BCount += n;
2159 n &= ~PacketMask;
2160 if(n>PS) {
2161 if(!OS_SUCCESS(status = Cache->ReadProc(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_ReadBytes, 0))) {
2162 status = WCacheRaiseIoError(Cache, Context, status, Lba+saved_BC-BCount, n, Buffer, WCACHE_R_OP, NULL);
2163 if(!OS_SUCCESS(status)) {
2164 goto EO_WCache_R;
2165 }
2166 }
2167 // WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2168 BCount -= n;
2169 Lba += saved_BC - BCount;
2170 saved_BC = BCount;
2171 i += n;
2172 Buffer += BS*n;
2173 *ReadBytes += BS*n;
2174 }
2175 // } else {
2176 // UDFPrint(("Unaligned\n"));
2177 }
2178 // read non-cached extent (if any)
2179 // firstable, we'll get total number of sectors to read
2180 to_read = 0;
2181 saved_i = i;
2182 d = BCount;
2183 while(d &&
2184 (i < Cache->BlocksPerFrame) &&
2185 (!WCacheSectorAddr(block_array, i)) ) {
2186 i++;
2187 to_read += BS;
2188 d--;
2189 }
2190 // read some not cached sectors
2191 if(to_read) {
2192 i = saved_i;
2193 saved_to_read = to_read;
2194 d = BCount - d;
2195 // split request if necessary
2196 if(saved_to_read > MaxR) {
2197 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2198 n = MaxR >> BSh;
2199 do {
2200 status = Cache->ReadProc(Context, Buffer, MaxR, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0);
2201 *ReadBytes += _ReadBytes;
2202 if(!OS_SUCCESS(status)) {
2203 _ReadBytes &= ~(BS-1);
2204 BCount -= _ReadBytes >> BSh;
2205 saved_to_read -= _ReadBytes;
2206 Buffer += _ReadBytes;
2207 saved_BC = BCount;
2208 goto store_read_data_1;
2209 }
2210 Buffer += MaxR;
2211 saved_to_read -= MaxR;
2212 i += n;
2213 BCount -= n;
2214 d -= n;
2215 } while(saved_to_read > MaxR);
2216 saved_BC = BCount;
2217 }
2218 if(saved_to_read) {
2219 status = Cache->ReadProc(Context, Buffer, saved_to_read, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0);
2220 *ReadBytes += _ReadBytes;
2221 if(!OS_SUCCESS(status)) {
2222 _ReadBytes &= ~(BS-1);
2223 BCount -= _ReadBytes >> BSh;
2224 saved_to_read -= _ReadBytes;
2225 Buffer += _ReadBytes;
2226 goto store_read_data_1;
2227 }
2228 Buffer += saved_to_read;
2229 saved_to_read = 0;
2230 BCount -= d;
2231 }
2232
2233 store_read_data_1:
2234 // and now we'll copy them to cache
2235
2236 //
2237 Buffer -= (to_read - saved_to_read);
2238 i = saved_i;
2239 while(to_read - saved_to_read) {
2240 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
2241 if(!block_array[i].Sector) {
2242 BCount += to_read >> BSh;
2243 status = STATUS_INSUFFICIENT_RESOURCES;
2244 goto EO_WCache_R;
2245 }
2246 DbgCopyMemory(block_array[i].Sector, Buffer, BS);
2247 Cache->FrameList[frame].BlockCount++;
2248 i++;
2249 Buffer += BS;
2250 to_read -= BS;
2251 }
2252 if(!OS_SUCCESS(status))
2253 goto EO_WCache_R;
2254 to_read = 0;
2255 }
2256 }
2257
2258 EO_WCache_R:
2259
2260 // we know the number of unread sectors if an error occured
2261 // so we can need to update BlockCount
2262 // return number of read bytes
2263 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2264 // Cache->FrameList[frame].BlockCount -= BCount;
2265 EO_WCache_R2:
2266 if(!CachedOnly) {
2267 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2268 }
2269
2270 return status;
2271 } // end WCacheReadBlocks__()
2272
2273 /*
2274 WCacheWriteBlocks__() writes data to cache.
2275 Data is written directly to media if:
2276 1) requested block is Packet-aligned
2277 2) requested Lba(s) lays beyond cached area
2278 Public routine
2279 */
2280 OSSTATUS
WCacheWriteBlocks__(IN PW_CACHE Cache,IN PVOID Context,IN PCHAR Buffer,IN lba_t Lba,IN ULONG BCount,OUT PSIZE_T WrittenBytes,IN BOOLEAN CachedOnly)2281 WCacheWriteBlocks__(
2282 IN PW_CACHE Cache, // pointer to the Cache Control structure
2283 IN PVOID Context, // user-supplied context for IO callbacks
2284 IN PCHAR Buffer, // user-supplied buffer containing data to be written
2285 IN lba_t Lba, // LBA to start write from
2286 IN ULONG BCount, // number of blocks to be written
2287 OUT PSIZE_T WrittenBytes, // user-supplied pointer to ULONG that will
2288 // recieve number of actually written bytes
2289 IN BOOLEAN CachedOnly // specifies that cache is already locked
2290 )
2291 {
2292 ULONG frame;
2293 ULONG i, saved_BC = BCount, n, d;
2294 OSSTATUS status = STATUS_SUCCESS;
2295 PW_CACHE_ENTRY block_array;
2296 ULONG BSh = Cache->BlockSizeSh;
2297 ULONG BS = Cache->BlockSize;
2298 PCHAR addr;
2299 // PCHAR saved_buff = Buffer;
2300 SIZE_T _WrittenBytes;
2301 ULONG PS = Cache->PacketSize;
2302 ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n
2303 ULONG block_type;
2304 // BOOLEAN Aligned = FALSE;
2305
2306 BOOLEAN WriteThrough = FALSE;
2307 lba_t WTh_Lba;
2308 ULONG WTh_BCount;
2309
2310 WcPrint(("WC:W %x (%x)\n", Lba, BCount));
2311
2312 *WrittenBytes = 0;
2313 // UDFPrint(("BCount:%x\n",BCount));
2314 // check if we try to read too much data
2315 if(BCount >= Cache->MaxBlocks) {
2316 i = 0;
2317 if(CachedOnly) {
2318 status = STATUS_INVALID_PARAMETER;
2319 goto EO_WCache_W2;
2320 }
2321 while(TRUE) {
2322 // UDFPrint((" BCount:%x\n",BCount));
2323 status = WCacheWriteBlocks__(Cache, Context, Buffer + (i<<BSh), Lba, min(PS,BCount), &_WrittenBytes, FALSE);
2324 (*WrittenBytes) += _WrittenBytes;
2325 BCount -= PS;
2326 Lba += PS;
2327 i += PS;
2328 if(!OS_SUCCESS(status) || (BCount < PS))
2329 return status;
2330 }
2331 }
2332 // check if we try to access beyond cached area
2333 if((Lba < Cache->FirstLba) ||
2334 (Lba + BCount - 1 > Cache->LastLba)) {
2335 return STATUS_INVALID_PARAMETER;
2336 }
2337 if(!CachedOnly) {
2338 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2339 }
2340
2341 frame = Lba >> Cache->BlocksPerFrameSh;
2342 i = Lba - (frame << Cache->BlocksPerFrameSh);
2343
2344 if(!CachedOnly &&
2345 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) {
2346 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2347 return status;
2348 }
2349
2350 // assume successful operation
2351 block_array = Cache->FrameList[frame].Frame;
2352 if(!block_array) {
2353
2354 if(BCount && !(BCount & (PS-1)) && !(Lba & (PS-1)) &&
2355 (Cache->Mode != WCACHE_MODE_R) &&
2356 (i+BCount <= Cache->BlocksPerFrame) &&
2357 !Cache->NoWriteThrough) {
2358 status = Cache->WriteProc(Context, Buffer, BCount<<BSh, Lba, WrittenBytes, 0);
2359 if(!OS_SUCCESS(status)) {
2360 status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_W_OP, NULL);
2361 }
2362 goto EO_WCache_W2;
2363 }
2364
2365 ASSERT(!CachedOnly);
2366 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2367 block_array = WCacheInitFrame(Cache, Context, frame);
2368 if(!block_array) {
2369 status = STATUS_INSUFFICIENT_RESOURCES;
2370 goto EO_WCache_W;
2371 }
2372 }
2373
2374 if(Cache->Mode == WCACHE_MODE_RAM &&
2375 BCount &&
2376 // !(Lba & (PS-1)) &&
2377 (!(BCount & (PS-1)) || (BCount > PS)) ) {
2378 WriteThrough = TRUE;
2379 WTh_Lba = Lba;
2380 WTh_BCount = BCount;
2381 } else
2382 if(Cache->Mode == WCACHE_MODE_RAM &&
2383 ((Lba & ~PacketMask) != ((Lba+BCount-1) & ~PacketMask))
2384 ) {
2385 WriteThrough = TRUE;
2386 WTh_Lba = Lba & ~PacketMask;
2387 WTh_BCount = PS;
2388 }
2389
2390 Cache->FrameList[frame].UpdateCount++;
2391 // UDFPrint((" BCount:%x\n",BCount));
2392 while(BCount) {
2393 if(i >= Cache->BlocksPerFrame) {
2394 frame++;
2395 block_array = Cache->FrameList[frame].Frame;
2396 i -= Cache->BlocksPerFrame;
2397 }
2398 if(!block_array) {
2399 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2400 block_array = WCacheInitFrame(Cache, Context, frame);
2401 if(!block_array) {
2402 status = STATUS_INSUFFICIENT_RESOURCES;
2403 goto EO_WCache_W;
2404 }
2405 }
2406 // 'write' cached extent (if any)
2407 // it is just copying
2408 while(BCount &&
2409 (i < Cache->BlocksPerFrame) &&
2410 (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) {
2411 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",addr, Buffer, BS, BCount));
2412 block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount);
2413 if(Cache->NoWriteBB &&
2414 /*WCacheGetBadFlag(block_array,i)*/
2415 (block_type & WCACHE_BLOCK_BAD)) {
2416 // bad packet. no cached write
2417 status = STATUS_DEVICE_DATA_ERROR;
2418 goto EO_WCache_W;
2419 }
2420 DbgCopyMemory(addr, Buffer, BS);
2421 WCacheSetModFlag(block_array, i);
2422 Buffer += BS;
2423 *WrittenBytes += BS;
2424 i++;
2425 BCount--;
2426 }
2427 // write non-cached not-aligned extent (if any) till aligned one
2428 while(BCount &&
2429 (i & PacketMask) &&
2430 (Cache->Mode != WCACHE_MODE_R) &&
2431 (i < Cache->BlocksPerFrame) &&
2432 (!WCacheSectorAddr(block_array, i)) ) {
2433 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
2434 if(!block_array[i].Sector) {
2435 status = STATUS_INSUFFICIENT_RESOURCES;
2436 goto EO_WCache_W;
2437 }
2438 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount));
2439 DbgCopyMemory(block_array[i].Sector, Buffer, BS);
2440 WCacheSetModFlag(block_array, i);
2441 i++;
2442 Buffer += BS;
2443 *WrittenBytes += BS;
2444 BCount--;
2445 Cache->FrameList[frame].BlockCount ++;
2446 }
2447 // write non-cached packet-size-aligned extent (if any)
2448 // now we'll calculate total length & decide if has enough size
2449 if(!Cache->NoWriteThrough
2450 &&
2451 ( !(i & PacketMask) ||
2452 ((Cache->Mode == WCACHE_MODE_R) && (BCount >= PS)) )) {
2453 n = 0;
2454 while(BCount &&
2455 (i < Cache->BlocksPerFrame) &&
2456 (!WCacheSectorAddr(block_array, i)) ) {
2457 n++;
2458 BCount--;
2459 }
2460 BCount += n;
2461 n &= ~PacketMask;
2462 // if(!OS_SUCCESS(status = Cache->WriteProcAsync(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_WrittenBytes, FALSE)))
2463 if(n) {
2464 // add previously written data to list
2465 d = saved_BC - BCount;
2466 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, d);
2467 WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d);
2468 Lba += d;
2469 saved_BC = BCount;
2470
2471 while(n) {
2472 if(Cache->Mode == WCACHE_MODE_R)
2473 Cache->UpdateRelocProc(Context, Lba, NULL, PS);
2474 if(!OS_SUCCESS(status = Cache->WriteProc(Context, Buffer, PS<<BSh, Lba, &_WrittenBytes, 0))) {
2475 status = WCacheRaiseIoError(Cache, Context, status, Lba, PS, Buffer, WCACHE_W_OP, NULL);
2476 if(!OS_SUCCESS(status)) {
2477 goto EO_WCache_W;
2478 }
2479 }
2480 BCount -= PS;
2481 Lba += PS;
2482 saved_BC = BCount;
2483 i += PS;
2484 Buffer += PS<<BSh;
2485 *WrittenBytes += PS<<BSh;
2486 n-=PS;
2487 }
2488 }
2489 }
2490 // write non-cached not-aligned extent (if any)
2491 while(BCount &&
2492 (i < Cache->BlocksPerFrame) &&
2493 (!WCacheSectorAddr(block_array, i)) ) {
2494 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
2495 if(!block_array[i].Sector) {
2496 status = STATUS_INSUFFICIENT_RESOURCES;
2497 goto EO_WCache_W;
2498 }
2499 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount));
2500 DbgCopyMemory(block_array[i].Sector, Buffer, BS);
2501 WCacheSetModFlag(block_array, i);
2502 i++;
2503 Buffer += BS;
2504 *WrittenBytes += BS;
2505 BCount--;
2506 Cache->FrameList[frame].BlockCount ++;
2507 }
2508 }
2509
2510 EO_WCache_W:
2511
2512 // we know the number of unread sectors if an error occured
2513 // so we can need to update BlockCount
2514 // return number of read bytes
2515 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2516 WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, saved_BC - BCount);
2517
2518 if(WriteThrough && !BCount) {
2519 ULONG d;
2520 // lba_t lastLba;
2521 ULONG firstPos;
2522 ULONG lastPos;
2523
2524 BCount = WTh_BCount;
2525 Lba = WTh_Lba;
2526 while(BCount) {
2527 frame = Lba >> Cache->BlocksPerFrameSh;
2528 // firstLba = frame << Cache->BlocksPerFrameSh;
2529 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba);
2530 d = min(Lba+BCount, (frame+1) << Cache->BlocksPerFrameSh) - Lba;
2531 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba+d);
2532 block_array = Cache->FrameList[frame].Frame;
2533 if(!block_array) {
2534 ASSERT(FALSE);
2535 BCount -= d;
2536 Lba += d;
2537 continue;
2538 }
2539 status = WCacheFlushBlocksRAM(Cache, Context, block_array, Cache->CachedBlocksList, firstPos, lastPos, FALSE);
2540 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d);
2541 BCount -= d;
2542 Lba += d;
2543 }
2544 }
2545
2546 EO_WCache_W2:
2547
2548 if(!CachedOnly) {
2549 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2550 }
2551 return status;
2552 } // end WCacheWriteBlocks__()
2553
2554 /*
2555 WCacheFlushAll__() copies all data stored in cache to media.
2556 Flushed blocks are kept in cache.
2557 Public routine
2558 */
2559 VOID
WCacheFlushAll__(IN PW_CACHE Cache,IN PVOID Context)2560 WCacheFlushAll__(
2561 IN PW_CACHE Cache, // pointer to the Cache Control structure
2562 IN PVOID Context) // user-supplied context for IO callbacks
2563 {
2564 if(!(Cache->ReadProc)) return;
2565 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2566
2567 switch(Cache->Mode) {
2568 case WCACHE_MODE_RAM:
2569 WCacheFlushAllRAM(Cache, Context);
2570 break;
2571 case WCACHE_MODE_ROM:
2572 case WCACHE_MODE_RW:
2573 WCacheFlushAllRW(Cache, Context);
2574 break;
2575 case WCACHE_MODE_R:
2576 WCachePurgeAllR(Cache, Context);
2577 break;
2578 }
2579
2580 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2581 return;
2582 } // end WCacheFlushAll__()
2583
2584 /*
2585 WCachePurgeAll__() copies all data stored in cache to media.
2586 Flushed blocks are removed cache.
2587 Public routine
2588 */
2589 VOID
WCachePurgeAll__(IN PW_CACHE Cache,IN PVOID Context)2590 WCachePurgeAll__(
2591 IN PW_CACHE Cache, // pointer to the Cache Control structure
2592 IN PVOID Context) // user-supplied context for IO callbacks
2593 {
2594 if(!(Cache->ReadProc)) return;
2595 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2596
2597 switch(Cache->Mode) {
2598 case WCACHE_MODE_RAM:
2599 WCachePurgeAllRAM(Cache, Context);
2600 break;
2601 case WCACHE_MODE_ROM:
2602 case WCACHE_MODE_RW:
2603 WCachePurgeAllRW(Cache, Context);
2604 break;
2605 case WCACHE_MODE_R:
2606 WCachePurgeAllR(Cache, Context);
2607 break;
2608 }
2609
2610 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2611 return;
2612 } // end WCachePurgeAll__()
2613 /*
2614 WCachePurgeAllRW() copies modified blocks from cache to media
2615 and removes them from cache
2616 This routine can be used for RAM, RW and ROM media.
2617 For ROM media blocks are just removed.
2618 Internal routine
2619 */
2620 VOID
2621 __fastcall
WCachePurgeAllRW(IN PW_CACHE Cache,IN PVOID Context)2622 WCachePurgeAllRW(
2623 IN PW_CACHE Cache, // pointer to the Cache Control structure
2624 IN PVOID Context) // user-supplied context for IO callbacks
2625 {
2626 ULONG frame;
2627 lba_t firstLba;
2628 lba_t* List = Cache->CachedBlocksList;
2629 lba_t Lba;
2630 // ULONG firstPos;
2631 // ULONG lastPos;
2632 ULONG BSh = Cache->BlockSizeSh;
2633 ULONG BS = Cache->BlockSize;
2634 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
2635 ULONG PSs = Cache->PacketSize;
2636 PW_CACHE_ENTRY block_array;
2637 // OSSTATUS status;
2638 SIZE_T ReadBytes;
2639 PW_CACHE_ASYNC FirstWContext = NULL;
2640 PW_CACHE_ASYNC PrevWContext = NULL;
2641 ULONG chain_count = 0;
2642
2643 if(!(Cache->ReadProc)) return;
2644
2645 while(Cache->BlockCount) {
2646 Lba = List[0] & ~(PSs-1);
2647 frame = Lba >> Cache->BlocksPerFrameSh;
2648 firstLba = frame << Cache->BlocksPerFrameSh;
2649 // firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba);
2650 // lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs);
2651 block_array = Cache->FrameList[frame].Frame;
2652 if(!block_array) {
2653 BrutePoint();
2654 return;
2655 }
2656
2657 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
2658 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE);
2659
2660 // free memory
2661 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs);
2662
2663 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs);
2664 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs);
2665 // check if frame is empty
2666 if(!(Cache->FrameList[frame].BlockCount)) {
2667 WCacheRemoveFrame(Cache, Context, frame);
2668 } else {
2669 ASSERT(Cache->FrameList[frame].Frame);
2670 }
2671 chain_count++;
2672 if(chain_count >= WCACHE_MAX_CHAIN) {
2673 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2674 chain_count = 0;
2675 }
2676 }
2677 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext);
2678 return;
2679 } // end WCachePurgeAllRW()
2680
2681 /*
2682 WCacheFlushAllRW() copies modified blocks from cache to media.
2683 All blocks are not removed from cache.
2684 This routine can be used for RAM, RW and ROM media.
2685 Internal routine
2686 */
2687 VOID
2688 __fastcall
WCacheFlushAllRW(IN PW_CACHE Cache,IN PVOID Context)2689 WCacheFlushAllRW(
2690 IN PW_CACHE Cache, // pointer to the Cache Control structure
2691 IN PVOID Context) // user-supplied context for IO callbacks
2692 {
2693 ULONG frame;
2694 lba_t firstLba;
2695 lba_t* List = Cache->CachedModifiedBlocksList;
2696 lba_t Lba;
2697 // ULONG firstPos;
2698 // ULONG lastPos;
2699 ULONG BSh = Cache->BlockSizeSh;
2700 ULONG BS = Cache->BlockSize;
2701 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
2702 ULONG PSs = Cache->PacketSize;
2703 ULONG BFs = Cache->BlocksPerFrameSh;
2704 PW_CACHE_ENTRY block_array;
2705 // OSSTATUS status;
2706 SIZE_T ReadBytes;
2707 PW_CACHE_ASYNC FirstWContext = NULL;
2708 PW_CACHE_ASYNC PrevWContext = NULL;
2709 ULONG i;
2710 ULONG chain_count = 0;
2711
2712 if(!(Cache->ReadProc)) return;
2713
2714 // walk through modified blocks
2715 while(Cache->WriteCount) {
2716 Lba = List[0] & ~(PSs-1);
2717 frame = Lba >> BFs;
2718 firstLba = frame << BFs;
2719 // firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba);
2720 // lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs);
2721 block_array = Cache->FrameList[frame].Frame;
2722 if(!block_array) {
2723 BrutePoint();
2724 continue;;
2725 }
2726 // queue modify request
2727 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
2728 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE);
2729 // clear MODIFIED flag for queued blocks
2730 WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs);
2731 Lba -= firstLba;
2732 for(i=0; i<PSs; i++) {
2733 WCacheClrModFlag(block_array, Lba+i);
2734 }
2735 chain_count++;
2736 // check queue size
2737 if(chain_count >= WCACHE_MAX_CHAIN) {
2738 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2739 chain_count = 0;
2740 }
2741 }
2742 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2743 #ifdef DBG
2744 #if 1
2745 // check consistency
2746 List = Cache->CachedBlocksList;
2747 for(i=0; i<Cache->BlockCount; i++) {
2748 Lba = List[i] /*& ~(PSs-1)*/;
2749 frame = Lba >> Cache->BlocksPerFrameSh;
2750 firstLba = frame << Cache->BlocksPerFrameSh;
2751 block_array = Cache->FrameList[frame].Frame;
2752 if(!block_array) {
2753 BrutePoint();
2754 }
2755 ASSERT(!WCacheGetModFlag(block_array, Lba-firstLba));
2756 }
2757 #endif // 1
2758 #endif // DBG
2759 return;
2760 } // end WCacheFlushAllRW()
2761
2762 /*
2763 WCacheRelease__() frees all allocated memory blocks and
2764 deletes synchronization resources
2765 Public routine
2766 */
2767 VOID
WCacheRelease__(IN PW_CACHE Cache)2768 WCacheRelease__(
2769 IN PW_CACHE Cache // pointer to the Cache Control structure
2770 )
2771 {
2772 ULONG i, j, k;
2773 PW_CACHE_ENTRY block_array;
2774
2775 Cache->Tag = 0xDEADCACE;
2776 if(!(Cache->ReadProc)) return;
2777 // ASSERT(Cache->Tag == 0xCAC11E00);
2778 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2779 for(i=0; i<Cache->FrameCount; i++) {
2780 j = Cache->CachedFramesList[i];
2781 block_array = Cache->FrameList[j].Frame;
2782 if(block_array) {
2783 for(k=0; k<Cache->BlocksPerFrame; k++) {
2784 if(WCacheSectorAddr(block_array, k)) {
2785 WCacheFreeSector(j, k);
2786 }
2787 }
2788 MyFreePool__(block_array);
2789 }
2790 }
2791 if(Cache->FrameList)
2792 MyFreePool__(Cache->FrameList);
2793 if(Cache->CachedBlocksList)
2794 MyFreePool__(Cache->CachedBlocksList);
2795 if(Cache->CachedModifiedBlocksList)
2796 MyFreePool__(Cache->CachedModifiedBlocksList);
2797 if(Cache->CachedFramesList)
2798 MyFreePool__(Cache->CachedFramesList);
2799 if(Cache->tmp_buff_r)
2800 MyFreePool__(Cache->tmp_buff_r);
2801 if(Cache->CachedFramesList)
2802 MyFreePool__(Cache->tmp_buff);
2803 if(Cache->CachedFramesList)
2804 MyFreePool__(Cache->reloc_tab);
2805 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2806 ExDeleteResourceLite(&(Cache->WCacheLock));
2807 RtlZeroMemory(Cache, sizeof(W_CACHE));
2808 return;
2809 } // end WCacheRelease__()
2810
2811 /*
2812 WCacheIsInitialized__() checks if the pointer supplied points
2813 to initialized cache structure.
2814 Public routine
2815 */
2816 BOOLEAN
WCacheIsInitialized__(IN PW_CACHE Cache)2817 WCacheIsInitialized__(
2818 IN PW_CACHE Cache
2819 )
2820 {
2821 return (Cache->ReadProc != NULL);
2822 } // end WCacheIsInitialized__()
2823
2824 OSSTATUS
WCacheFlushBlocksRW(IN PW_CACHE Cache,IN PVOID Context,IN lba_t _Lba,IN ULONG BCount)2825 WCacheFlushBlocksRW(
2826 IN PW_CACHE Cache, // pointer to the Cache Control structure
2827 IN PVOID Context, // user-supplied context for IO callbacks
2828 IN lba_t _Lba, // LBA to start flush from
2829 IN ULONG BCount // number of blocks to be flushed
2830 )
2831 {
2832 ULONG frame;
2833 lba_t firstLba;
2834 lba_t* List = Cache->CachedModifiedBlocksList;
2835 lba_t Lba;
2836 // ULONG firstPos;
2837 // ULONG lastPos;
2838 ULONG BSh = Cache->BlockSizeSh;
2839 ULONG BS = Cache->BlockSize;
2840 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
2841 ULONG PSs = Cache->PacketSize;
2842 ULONG BFs = Cache->BlocksPerFrameSh;
2843 PW_CACHE_ENTRY block_array;
2844 // OSSTATUS status;
2845 SIZE_T ReadBytes;
2846 PW_CACHE_ASYNC FirstWContext = NULL;
2847 PW_CACHE_ASYNC PrevWContext = NULL;
2848 ULONG i;
2849 ULONG chain_count = 0;
2850 lba_t lim;
2851
2852 if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER;
2853
2854 // walk through modified blocks
2855 lim = (_Lba+BCount+PSs-1) & ~(PSs-1);
2856 for(Lba = _Lba & ~(PSs-1);Lba < lim ; Lba += PSs) {
2857 frame = Lba >> BFs;
2858 firstLba = frame << BFs;
2859 // firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba);
2860 // lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs);
2861 block_array = Cache->FrameList[frame].Frame;
2862 if(!block_array) {
2863 // not cached block may be requested for flush
2864 Lba += (1 << BFs) - PSs;
2865 continue;
2866 }
2867 // queue modify request
2868 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
2869 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE);
2870 // clear MODIFIED flag for queued blocks
2871 WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs);
2872 Lba -= firstLba;
2873 for(i=0; i<PSs; i++) {
2874 WCacheClrModFlag(block_array, Lba+i);
2875 }
2876 Lba += firstLba;
2877 chain_count++;
2878 // check queue size
2879 if(chain_count >= WCACHE_MAX_CHAIN) {
2880 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2881 chain_count = 0;
2882 }
2883 }
2884 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2885 /*
2886 if(Cache->Mode != WCACHE_MODE_RAM)
2887 return STATUS_SUCCESS;
2888 */
2889
2890 return STATUS_SUCCESS;
2891 } // end WCacheFlushBlocksRW()
2892
2893 /*
2894 WCacheFlushBlocks__() copies specified blocks stored in cache to media.
2895 Flushed blocks are kept in cache.
2896 Public routine
2897 */
2898 OSSTATUS
WCacheFlushBlocks__(IN PW_CACHE Cache,IN PVOID Context,IN lba_t Lba,IN ULONG BCount)2899 WCacheFlushBlocks__(
2900 IN PW_CACHE Cache, // pointer to the Cache Control structure
2901 IN PVOID Context, // user-supplied context for IO callbacks
2902 IN lba_t Lba, // LBA to start flush from
2903 IN ULONG BCount // number of blocks to be flushed
2904 )
2905 {
2906 OSSTATUS status;
2907
2908 if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER;
2909 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2910
2911 // check if we try to access beyond cached area
2912 if((Lba < Cache->FirstLba) ||
2913 (Lba+BCount-1 > Cache->LastLba)) {
2914 UDFPrint(("LBA %#x (%x) is beyond cacheable area\n", Lba, BCount));
2915 BrutePoint();
2916 status = STATUS_INVALID_PARAMETER;
2917 goto EO_WCache_F;
2918 }
2919
2920 switch(Cache->Mode) {
2921 case WCACHE_MODE_RAM:
2922 // WCacheFlushBlocksRW(Cache, Context);
2923 // break;
2924 case WCACHE_MODE_ROM:
2925 case WCACHE_MODE_RW:
2926 status = WCacheFlushBlocksRW(Cache, Context, Lba, BCount);
2927 break;
2928 case WCACHE_MODE_R:
2929 status = STATUS_SUCCESS;
2930 break;
2931 }
2932 EO_WCache_F:
2933 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2934 return status;
2935 } // end WCacheFlushBlocks__()
2936
2937 /*
2938 WCacheDirect__() returns pointer to memory block where
2939 requested block is stored in.
2940 If no #CachedOnly flag specified this routine locks cache,
2941 otherwise it assumes that cache is already locked by previous call
2942 to WCacheStartDirect__().
2943 Cache can be unlocked by WCacheEODirect__().
2944 Using this routine caller can access cached block directly in memory
2945 without Read_to_Tmp and Modify/Write steps.
2946 Public routine
2947 */
2948 OSSTATUS
WCacheDirect__(IN PW_CACHE Cache,IN PVOID Context,IN lba_t Lba,IN BOOLEAN Modified,OUT PCHAR * CachedBlock,IN BOOLEAN CachedOnly)2949 WCacheDirect__(
2950 IN PW_CACHE Cache, // pointer to the Cache Control structure
2951 IN PVOID Context, // user-supplied context for IO callbacks
2952 IN lba_t Lba, // LBA of block to get pointer to
2953 IN BOOLEAN Modified, // indicates that block will be modified
2954 OUT PCHAR* CachedBlock, // address for pointer to cached block to be stored in
2955 IN BOOLEAN CachedOnly // specifies that cache is already locked
2956 )
2957 {
2958 ULONG frame;
2959 ULONG i;
2960 OSSTATUS status = STATUS_SUCCESS;
2961 PW_CACHE_ENTRY block_array;
2962 ULONG BS = Cache->BlockSize;
2963 PCHAR addr;
2964 SIZE_T _ReadBytes;
2965 ULONG block_type;
2966
2967 WcPrint(("WC:%sD %x (1)\n", Modified ? "W" : "R", Lba));
2968
2969 // lock cache if nececcary
2970 if(!CachedOnly) {
2971 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2972 }
2973 // check if we try to access beyond cached area
2974 if((Lba < Cache->FirstLba) ||
2975 (Lba > Cache->LastLba)) {
2976 UDFPrint(("LBA %#x is beyond cacheable area\n", Lba));
2977 BrutePoint();
2978 status = STATUS_INVALID_PARAMETER;
2979 goto EO_WCache_D;
2980 }
2981
2982 frame = Lba >> Cache->BlocksPerFrameSh;
2983 i = Lba - (frame << Cache->BlocksPerFrameSh);
2984 // check if we have enough space to store requested block
2985 if(!CachedOnly &&
2986 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, 1))) {
2987 BrutePoint();
2988 goto EO_WCache_D;
2989 }
2990
2991 // small updates are more important
2992 block_array = Cache->FrameList[frame].Frame;
2993 if(Modified) {
2994 Cache->FrameList[frame].UpdateCount+=8;
2995 } else {
2996 Cache->FrameList[frame].AccessCount+=8;
2997 }
2998 if(!block_array) {
2999 ASSERT(Cache->FrameCount < Cache->MaxFrames);
3000 block_array = WCacheInitFrame(Cache, Context, frame);
3001 if(!block_array) {
3002 status = STATUS_INSUFFICIENT_RESOURCES;
3003 goto EO_WCache_D;
3004 }
3005 }
3006 // check if requested block is already cached
3007 if( !(addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) {
3008 // block is not cached
3009 // allocate memory and read block from media
3010 // do not set block_array[i].Sector here, because if media access fails and recursive access to cache
3011 // comes, this block should not be marked as 'cached'
3012 addr = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
3013 if(!addr) {
3014 status = STATUS_INSUFFICIENT_RESOURCES;
3015 goto EO_WCache_D;
3016 }
3017 block_type = Cache->CheckUsedProc(Context, Lba);
3018 if(block_type == WCACHE_BLOCK_USED) {
3019 status = Cache->ReadProc(Context, addr, BS, Lba, &_ReadBytes, PH_TMP_BUFFER);
3020 if(Cache->RememberBB) {
3021 if(!OS_SUCCESS(status)) {
3022 RtlZeroMemory(addr, BS);
3023 //WCacheSetBadFlag(block_array,i);
3024 }
3025 }
3026 } else {
3027 if(block_type & WCACHE_BLOCK_BAD) {
3028 DbgFreePool(addr);
3029 addr = NULL;
3030 status = STATUS_DEVICE_DATA_ERROR;
3031 goto EO_WCache_D;
3032 }
3033 if(!(block_type & WCACHE_BLOCK_ZERO)) {
3034 BrutePoint();
3035 }
3036 status = STATUS_SUCCESS;
3037 RtlZeroMemory(addr, BS);
3038 }
3039 // now add pointer to buffer to common storage
3040 block_array[i].Sector = addr;
3041 WCacheInsertItemToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba);
3042 if(Modified) {
3043 WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3044 WCacheSetModFlag(block_array, i);
3045 }
3046 Cache->FrameList[frame].BlockCount ++;
3047 } else {
3048 // block is not cached
3049 // just return pointer
3050 block_type = Cache->CheckUsedProc(Context, Lba);
3051 if(block_type & WCACHE_BLOCK_BAD) {
3052 //if(WCacheGetBadFlag(block_array,i)) {
3053 // bad packet. no pre-read
3054 status = STATUS_DEVICE_DATA_ERROR;
3055 goto EO_WCache_D;
3056 }
3057 #ifndef UDF_CHECK_UTIL
3058 ASSERT(block_type & WCACHE_BLOCK_USED);
3059 #else
3060 if(!(block_type & WCACHE_BLOCK_USED)) {
3061 UDFPrint(("LBA %#x is not marked as used\n", Lba));
3062 }
3063 #endif
3064 if(Modified &&
3065 !WCacheGetModFlag(block_array, i)) {
3066 WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3067 WCacheSetModFlag(block_array, i);
3068 }
3069 }
3070 (*CachedBlock) = addr;
3071
3072 EO_WCache_D:
3073
3074 return status;
3075 } // end WCacheDirect__()
3076
3077 /*
3078 WCacheEODirect__() must be used to unlock cache after calls to
3079 to WCacheStartDirect__().
3080 Public routine
3081 */
3082 OSSTATUS
WCacheEODirect__(IN PW_CACHE Cache,IN PVOID Context)3083 WCacheEODirect__(
3084 IN PW_CACHE Cache, // pointer to the Cache Control structure
3085 IN PVOID Context // user-supplied context for IO callbacks
3086 )
3087 {
3088 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
3089 return STATUS_SUCCESS;
3090 } // end WCacheEODirect__()
3091
3092 /*
3093 WCacheStartDirect__() locks cache for exclusive use.
3094 Using this routine caller can access cached block directly in memory
3095 without Read_to_Tmp and Modify/Write steps.
3096 See also WCacheDirect__()
3097 Cache can be unlocked by WCacheEODirect__().
3098 Public routine
3099 */
3100 OSSTATUS
WCacheStartDirect__(IN PW_CACHE Cache,IN PVOID Context,IN BOOLEAN Exclusive)3101 WCacheStartDirect__(
3102 IN PW_CACHE Cache, // pointer to the Cache Control structure
3103 IN PVOID Context, // user-supplied context for IO callbacks
3104 IN BOOLEAN Exclusive // lock cache for exclusive use,
3105 // currently must be TRUE.
3106 )
3107 {
3108 if(Exclusive) {
3109 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
3110 } else {
3111 BrutePoint();
3112 ExAcquireResourceSharedLite(&(Cache->WCacheLock), TRUE);
3113 }
3114 return STATUS_SUCCESS;
3115 } // end WCacheStartDirect__()
3116
3117 /*
3118 WCacheIsCached__() checks if requested blocks are immediately available.
3119 Cache must be previously locked for exclusive use with WCacheStartDirect__().
3120 Using this routine caller can access cached block directly in memory
3121 without Read_to_Tmp and Modify/Write steps.
3122 See also WCacheDirect__().
3123 Cache can be unlocked by WCacheEODirect__().
3124 Public routine
3125 */
3126 BOOLEAN
WCacheIsCached__(IN PW_CACHE Cache,IN lba_t Lba,IN ULONG BCount)3127 WCacheIsCached__(
3128 IN PW_CACHE Cache, // pointer to the Cache Control structure
3129 IN lba_t Lba, // LBA to start check from
3130 IN ULONG BCount // number of blocks to be checked
3131 )
3132 {
3133 ULONG frame;
3134 ULONG i;
3135 PW_CACHE_ENTRY block_array;
3136
3137 // check if we try to access beyond cached area
3138 if((Lba < Cache->FirstLba) ||
3139 (Lba + BCount - 1 > Cache->LastLba)) {
3140 return FALSE;
3141 }
3142
3143 frame = Lba >> Cache->BlocksPerFrameSh;
3144 i = Lba - (frame << Cache->BlocksPerFrameSh);
3145
3146 block_array = Cache->FrameList[frame].Frame;
3147 if(!block_array) {
3148 return FALSE;
3149 }
3150
3151 while(BCount) {
3152 if(i >= Cache->BlocksPerFrame) {
3153 frame++;
3154 block_array = Cache->FrameList[frame].Frame;
3155 i -= Cache->BlocksPerFrame;
3156 }
3157 if(!block_array) {
3158 return FALSE;
3159 }
3160 // 'read' cached extent (if any)
3161 while(BCount &&
3162 (i < Cache->BlocksPerFrame) &&
3163 WCacheSectorAddr(block_array, i) &&
3164 /*!WCacheGetBadFlag(block_array, i)*/
3165 /*!(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_BAD)*/
3166 TRUE ) {
3167 i++;
3168 BCount--;
3169 Lba++;
3170 }
3171 if(BCount &&
3172 (i < Cache->BlocksPerFrame) /*&&
3173 (!WCacheSectorAddr(block_array, i))*/ ) {
3174 return FALSE;
3175 }
3176 }
3177 return TRUE;
3178 } // end WCacheIsCached__()
3179
3180 /*
3181 WCacheCheckLimitsR() implements automatic flush and purge of
3182 unused blocks to keep enough free cache entries for newly
3183 read/written blocks for WORM media.
3184 See also WCacheCheckLimits()
3185 Internal routine
3186 */
3187 OSSTATUS
3188 __fastcall
WCacheCheckLimitsR(IN PW_CACHE Cache,IN PVOID Context,IN lba_t ReqLba,IN ULONG BCount)3189 WCacheCheckLimitsR(
3190 IN PW_CACHE Cache, // pointer to the Cache Control structure
3191 IN PVOID Context, // user-supplied context for IO callbacks
3192 IN lba_t ReqLba, // first LBA to access/cache
3193 IN ULONG BCount // number of Blocks to access/cache
3194 )
3195 {
3196 ULONG frame;
3197 lba_t firstLba;
3198 lba_t* List = Cache->CachedBlocksList;
3199 lba_t Lba;
3200 PCHAR tmp_buff = Cache->tmp_buff;
3201 ULONG firstPos;
3202 ULONG BSh = Cache->BlockSizeSh;
3203 ULONG BS = Cache->BlockSize;
3204 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
3205 ULONG PSs = Cache->PacketSize;
3206 ULONG i;
3207 PW_CACHE_ENTRY block_array;
3208 BOOLEAN mod;
3209 OSSTATUS status;
3210 SIZE_T ReadBytes;
3211 ULONG MaxReloc = Cache->PacketSize;
3212 PULONG reloc_tab = Cache->reloc_tab;
3213
3214 // check if we try to read too much data
3215 if(BCount > Cache->MaxBlocks) {
3216 return STATUS_INVALID_PARAMETER;
3217 }
3218
3219 // remove(flush) packets from entire frame(s)
3220 while( ((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
3221 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) ||
3222 (Cache->FrameCount >= Cache->MaxFrames) ) {
3223
3224 WCCL_retry_1:
3225
3226 Lba = WCacheFindLbaToRelease(Cache);
3227 if(Lba == WCACHE_INVALID_LBA) {
3228 ASSERT(!Cache->FrameCount);
3229 ASSERT(!Cache->BlockCount);
3230 break;
3231 }
3232 frame = Lba >> Cache->BlocksPerFrameSh;
3233 firstLba = frame << Cache->BlocksPerFrameSh;
3234 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba);
3235 block_array = Cache->FrameList[frame].Frame;
3236 if(!block_array) {
3237 return STATUS_DRIVER_INTERNAL_ERROR;
3238 }
3239 // check if modified
3240 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3241 // read/modify/write
3242 if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) {
3243 if(Cache->WriteCount < MaxReloc) goto WCCL_retry_1;
3244 firstPos = WCacheGetSortedListIndex(Cache->WriteCount, Cache->CachedModifiedBlocksList, Lba);
3245 if(!block_array) {
3246 return STATUS_DRIVER_INTERNAL_ERROR;
3247 }
3248 // prepare packet & reloc table
3249 for(i=0; i<MaxReloc; i++) {
3250 Lba = Cache->CachedModifiedBlocksList[firstPos];
3251 frame = Lba >> Cache->BlocksPerFrameSh;
3252 firstLba = frame << Cache->BlocksPerFrameSh;
3253 block_array = Cache->FrameList[frame].Frame;
3254 DbgCopyMemory(tmp_buff + (i << BSh),
3255 (PVOID)WCacheSectorAddr(block_array, Lba-firstLba),
3256 BS);
3257 reloc_tab[i] = Lba;
3258 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3259 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3260 // mark as non-cached & free pool
3261 WCacheFreeSector(frame, Lba-firstLba);
3262 // check if frame is empty
3263 if(!Cache->FrameList[frame].BlockCount) {
3264 WCacheRemoveFrame(Cache, Context, frame);
3265 }
3266 if(firstPos >= Cache->WriteCount) firstPos=0;
3267 }
3268 // write packet
3269 // status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE);
3270 Cache->UpdateRelocProc(Context, NULL, reloc_tab, MaxReloc);
3271 status = Cache->WriteProc(Context, tmp_buff, PS, NULL, &ReadBytes, 0);
3272 if(!OS_SUCCESS(status)) {
3273 status = WCacheRaiseIoError(Cache, Context, status, NULL, PSs, tmp_buff, WCACHE_W_OP, NULL);
3274 }
3275 } else {
3276
3277 if((i = Cache->BlockCount - Cache->WriteCount) > MaxReloc) i = MaxReloc;
3278 // discard blocks
3279 for(; i; i--) {
3280 Lba = List[firstPos];
3281 frame = Lba >> Cache->BlocksPerFrameSh;
3282 firstLba = frame << Cache->BlocksPerFrameSh;
3283 block_array = Cache->FrameList[frame].Frame;
3284
3285 if( (mod = WCacheGetModFlag(block_array, Lba - firstLba)) &&
3286 (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED) )
3287 continue;
3288 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3289 if(mod)
3290 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3291 // mark as non-cached & free pool
3292 WCacheFreeSector(frame, Lba-firstLba);
3293 // check if frame is empty
3294 if(!Cache->FrameList[frame].BlockCount) {
3295 WCacheRemoveFrame(Cache, Context, frame);
3296 }
3297 if(firstPos >= Cache->WriteCount) firstPos=0;
3298 }
3299 }
3300 }
3301 return STATUS_SUCCESS;
3302 } // end WCacheCheckLimitsR()
3303
3304 /*
3305 WCachePurgeAllR() copies modified blocks from cache to media
3306 and removes them from cache
3307 This routine can be used for R media only.
3308 Internal routine
3309 */
3310 VOID
3311 __fastcall
WCachePurgeAllR(IN PW_CACHE Cache,IN PVOID Context)3312 WCachePurgeAllR(
3313 IN PW_CACHE Cache, // pointer to the Cache Control structure
3314 IN PVOID Context) // user-supplied context for IO callbacks
3315 {
3316 ULONG frame;
3317 lba_t firstLba;
3318 lba_t* List = Cache->CachedBlocksList;
3319 lba_t Lba;
3320 PCHAR tmp_buff = Cache->tmp_buff;
3321 ULONG BSh = Cache->BlockSizeSh;
3322 ULONG BS = Cache->BlockSize;
3323 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
3324 // ULONG PSs = Cache->PacketSize;
3325 PW_CACHE_ENTRY block_array;
3326 BOOLEAN mod;
3327 OSSTATUS status;
3328 SIZE_T ReadBytes;
3329 ULONG MaxReloc = Cache->PacketSize;
3330 PULONG reloc_tab = Cache->reloc_tab;
3331 ULONG RelocCount = 0;
3332 BOOLEAN IncompletePacket;
3333 ULONG i=0;
3334 ULONG PacketTail;
3335
3336 while(Cache->WriteCount < Cache->BlockCount) {
3337
3338 Lba = List[i];
3339 frame = Lba >> Cache->BlocksPerFrameSh;
3340 firstLba = frame << Cache->BlocksPerFrameSh;
3341 block_array = Cache->FrameList[frame].Frame;
3342 if(!block_array) {
3343 BrutePoint();
3344 return;
3345 }
3346 // check if modified
3347 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3348 // just discard
3349 if(!mod || !(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) {
3350 // mark as non-cached & free pool
3351 if(WCacheSectorAddr(block_array,Lba-firstLba)) {
3352 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3353 if(mod)
3354 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3355 // mark as non-cached & free pool
3356 WCacheFreeSector(frame, Lba-firstLba);
3357 // check if frame is empty
3358 if(!Cache->FrameList[frame].BlockCount) {
3359 WCacheRemoveFrame(Cache, Context, frame);
3360 }
3361 } else {
3362 BrutePoint();
3363 }
3364 } else {
3365 i++;
3366 }
3367 }
3368
3369 PacketTail = Cache->WriteCount & (MaxReloc-1);
3370 IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE;
3371
3372 // remove(flush) packet
3373 while((Cache->WriteCount > PacketTail) || (Cache->WriteCount && IncompletePacket)) {
3374
3375 Lba = List[0];
3376 frame = Lba >> Cache->BlocksPerFrameSh;
3377 firstLba = frame << Cache->BlocksPerFrameSh;
3378 block_array = Cache->FrameList[frame].Frame;
3379 if(!block_array) {
3380 BrutePoint();
3381 return;
3382 }
3383 // check if modified
3384 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3385 // pack/reloc/write
3386 if(mod) {
3387 DbgCopyMemory(tmp_buff + (RelocCount << BSh),
3388 (PVOID)WCacheSectorAddr(block_array, Lba-firstLba),
3389 BS);
3390 reloc_tab[RelocCount] = Lba;
3391 RelocCount++;
3392 // write packet
3393 if((RelocCount >= MaxReloc) || (Cache->BlockCount == 1)) {
3394 // status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE);
3395 Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount);
3396 status = Cache->WriteProc(Context, tmp_buff, RelocCount<<BSh, NULL, &ReadBytes, 0);
3397 if(!OS_SUCCESS(status)) {
3398 status = WCacheRaiseIoError(Cache, Context, status, NULL, RelocCount, tmp_buff, WCACHE_W_OP, NULL);
3399 }
3400 RelocCount = 0;
3401 }
3402 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3403 } else {
3404 BrutePoint();
3405 }
3406 // mark as non-cached & free pool
3407 if(WCacheSectorAddr(block_array,Lba-firstLba)) {
3408 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3409 // mark as non-cached & free pool
3410 WCacheFreeSector(frame, Lba-firstLba);
3411 // check if frame is empty
3412 if(!Cache->FrameList[frame].BlockCount) {
3413 WCacheRemoveFrame(Cache, Context, frame);
3414 }
3415 } else {
3416 BrutePoint();
3417 }
3418 }
3419 } // end WCachePurgeAllR()
3420
3421 /*
3422 WCacheSetMode__() changes cache operating mode (ROM/R/RW/RAM).
3423 Public routine
3424 */
3425 OSSTATUS
WCacheSetMode__(IN PW_CACHE Cache,IN ULONG Mode)3426 WCacheSetMode__(
3427 IN PW_CACHE Cache, // pointer to the Cache Control structure
3428 IN ULONG Mode // cache mode/media type to be used
3429 )
3430 {
3431 if(Mode > WCACHE_MODE_MAX) return STATUS_INVALID_PARAMETER;
3432 Cache->Mode = Mode;
3433 return STATUS_SUCCESS;
3434 } // end WCacheSetMode__()
3435
3436 /*
3437 WCacheGetMode__() returns cache operating mode (ROM/R/RW/RAM).
3438 Public routine
3439 */
3440 ULONG
WCacheGetMode__(IN PW_CACHE Cache)3441 WCacheGetMode__(
3442 IN PW_CACHE Cache
3443 )
3444 {
3445 return Cache->Mode;
3446 } // end WCacheGetMode__()
3447
3448 /*
3449 WCacheGetWriteBlockCount__() returns number of modified blocks, those are
3450 not flushed to media. Is usually used to preallocate blocks for
3451 relocation table on WORM (R) media.
3452 Public routine
3453 */
3454 ULONG
WCacheGetWriteBlockCount__(IN PW_CACHE Cache)3455 WCacheGetWriteBlockCount__(
3456 IN PW_CACHE Cache
3457 )
3458 {
3459 return Cache->WriteCount;
3460 } // end WCacheGetWriteBlockCount__()
3461
3462 /*
3463 WCacheSyncReloc__() builds list of all modified blocks, currently
3464 stored in cache. For each modified block WCacheSyncReloc__() calls
3465 user-supplied callback routine in order to update relocation table
3466 on WORM (R) media.
3467 Public routine
3468 */
3469 VOID
WCacheSyncReloc__(IN PW_CACHE Cache,IN PVOID Context)3470 WCacheSyncReloc__(
3471 IN PW_CACHE Cache,
3472 IN PVOID Context)
3473 {
3474 ULONG frame;
3475 lba_t firstLba;
3476 lba_t* List = Cache->CachedBlocksList;
3477 lba_t Lba;
3478 // ULONG BSh = Cache->BlockSizeSh;
3479 // ULONG BS = Cache->BlockSize;
3480 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
3481 // ULONG PSs = Cache->PacketSize;
3482 PW_CACHE_ENTRY block_array;
3483 BOOLEAN mod;
3484 ULONG MaxReloc = Cache->PacketSize;
3485 PULONG reloc_tab = Cache->reloc_tab;
3486 ULONG RelocCount = 0;
3487 BOOLEAN IncompletePacket;
3488
3489 IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE;
3490 // enumerate modified blocks
3491 for(ULONG i=0; IncompletePacket && (i<Cache->BlockCount); i++) {
3492
3493 Lba = List[i];
3494 frame = Lba >> Cache->BlocksPerFrameSh;
3495 firstLba = frame << Cache->BlocksPerFrameSh;
3496 block_array = Cache->FrameList[frame].Frame;
3497 if(!block_array) {
3498 return;
3499 }
3500 // check if modified
3501 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3502 // update relocation table for modified sectors
3503 if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) {
3504 reloc_tab[RelocCount] = Lba;
3505 RelocCount++;
3506 if(RelocCount >= Cache->WriteCount) {
3507 Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount);
3508 break;
3509 }
3510 }
3511 }
3512 } // end WCacheSyncReloc__()
3513
3514 /*
3515 WCacheDiscardBlocks__() removes specified blocks from cache.
3516 Blocks are not flushed to media.
3517 Public routine
3518 */
3519 VOID
WCacheDiscardBlocks__(IN PW_CACHE Cache,IN PVOID Context,IN lba_t ReqLba,IN ULONG BCount)3520 WCacheDiscardBlocks__(
3521 IN PW_CACHE Cache,
3522 IN PVOID Context,
3523 IN lba_t ReqLba,
3524 IN ULONG BCount
3525 )
3526 {
3527 ULONG frame;
3528 lba_t firstLba;
3529 lba_t* List;
3530 lba_t Lba;
3531 PW_CACHE_ENTRY block_array;
3532 BOOLEAN mod;
3533 ULONG i;
3534
3535 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
3536
3537 UDFPrint((" Discard req: %x@%x\n",BCount, ReqLba));
3538
3539 List = Cache->CachedBlocksList;
3540 if(!List) {
3541 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
3542 return;
3543 }
3544 i = WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba);
3545
3546 // enumerate requested blocks
3547 while((List[i] < (ReqLba+BCount)) && (i < Cache->BlockCount)) {
3548
3549 Lba = List[i];
3550 frame = Lba >> Cache->BlocksPerFrameSh;
3551 firstLba = frame << Cache->BlocksPerFrameSh;
3552 block_array = Cache->FrameList[frame].Frame;
3553 if(!block_array) {
3554 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
3555 BrutePoint();
3556 return;
3557 }
3558 // check if modified
3559 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3560 // just discard
3561
3562 // mark as non-cached & free pool
3563 if(WCacheSectorAddr(block_array,Lba-firstLba)) {
3564 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3565 if(mod)
3566 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3567 // mark as non-cached & free pool
3568 WCacheFreeSector(frame, Lba-firstLba);
3569 // check if frame is empty
3570 if(!Cache->FrameList[frame].BlockCount) {
3571 WCacheRemoveFrame(Cache, Context, frame);
3572 } else {
3573 ASSERT(Cache->FrameList[frame].Frame);
3574 }
3575 } else {
3576 // we should never get here !!!
3577 // getting this part of code means that we have
3578 // placed non-cached block in CachedBlocksList
3579 BrutePoint();
3580 }
3581 }
3582 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
3583 } // end WCacheDiscardBlocks__()
3584
3585 OSSTATUS
WCacheCompleteAsync__(IN PVOID WContext,IN OSSTATUS Status)3586 WCacheCompleteAsync__(
3587 IN PVOID WContext,
3588 IN OSSTATUS Status
3589 )
3590 {
3591 PW_CACHE_ASYNC AsyncCtx = (PW_CACHE_ASYNC)WContext;
3592 // PW_CACHE Cache = AsyncCtx->Cache;
3593
3594 AsyncCtx->PhContext.IosbToUse.Status = Status;
3595 KeSetEvent(&(AsyncCtx->PhContext.event), 0, FALSE);
3596
3597 return STATUS_SUCCESS;
3598 } // end WCacheSetMode__()
3599
3600 /*
3601 WCacheDecodeFlags() updates internal BOOLEANs according to Flags
3602 Internal routine
3603 */
3604 OSSTATUS
3605 __fastcall
WCacheDecodeFlags(IN PW_CACHE Cache,IN ULONG Flags)3606 WCacheDecodeFlags(
3607 IN PW_CACHE Cache, // pointer to the Cache Control structure
3608 IN ULONG Flags // cache mode flags
3609 )
3610 {
3611 //ULONG OldFlags;
3612 if(Flags & ~WCACHE_VALID_FLAGS) {
3613 UDFPrint(("Invalid flags: %x\n", Flags & ~WCACHE_VALID_FLAGS));
3614 return STATUS_INVALID_PARAMETER;
3615 }
3616 Cache->CacheWholePacket = (Flags & WCACHE_CACHE_WHOLE_PACKET) ? TRUE : FALSE;
3617 Cache->DoNotCompare = (Flags & WCACHE_DO_NOT_COMPARE) ? TRUE : FALSE;
3618 Cache->Chained = (Flags & WCACHE_CHAINED_IO) ? TRUE : FALSE;
3619 Cache->RememberBB = (Flags & WCACHE_MARK_BAD_BLOCKS) ? TRUE : FALSE;
3620 if(Cache->RememberBB) {
3621 Cache->NoWriteBB = (Flags & WCACHE_RO_BAD_BLOCKS) ? TRUE : FALSE;
3622 }
3623 Cache->NoWriteThrough = (Flags & WCACHE_NO_WRITE_THROUGH) ? TRUE : FALSE;
3624
3625 Cache->Flags = Flags;
3626
3627 return STATUS_SUCCESS;
3628 }
3629
3630 /*
3631 WCacheChFlags__() changes cache flags.
3632 Public routine
3633 */
3634 ULONG
WCacheChFlags__(IN PW_CACHE Cache,IN ULONG SetFlags,IN ULONG ClrFlags)3635 WCacheChFlags__(
3636 IN PW_CACHE Cache, // pointer to the Cache Control structure
3637 IN ULONG SetFlags, // cache mode/media type to be set
3638 IN ULONG ClrFlags // cache mode/media type to be cleared
3639 )
3640 {
3641 ULONG Flags;
3642
3643 if(SetFlags || ClrFlags) {
3644 Flags = (Cache->Flags & ~ClrFlags) | SetFlags;
3645
3646 if(!OS_SUCCESS(WCacheDecodeFlags(Cache, Flags))) {
3647 return -1;
3648 }
3649 } else {
3650 return Cache->Flags;
3651 }
3652 return Flags;
3653 } // end WCacheSetMode__()
3654