d0e15b79c746f964c78cc0ddebdebc406a204421
[reactos.git] / drivers / filesystems / udfs / Include / wcache_lib.cpp
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 if(Chained &&
1139 WContext->State == ASYNC_STATE_WRITE_PRE) {
1140 // Return if block is prepared for write and we are in chained mode.
1141 if(!mod) {
1142 // Mark block as written if we have found that data in it
1143 // is not actually modified.
1144 WContext->State = ASYNC_STATE_DONE;
1145 (*ReadBytes) = PS;
1146 }
1147 return STATUS_SUCCESS;
1148 }
1149
1150 // write packet
1151
1152 // If the check above reported some changes in packet
1153 // we should write packet out to media.
1154 // Otherwise, just complete request.
1155 if(mod) {
1156 try_write:
1157 if(Async) {
1158 WContext->State = ASYNC_STATE_WRITE;
1159 status = Cache->WriteProcAsync(Context, WContext, tmp_buff2, PS, Lba,
1160 &(WContext->TransferredBytes), FALSE);
1161 (*ReadBytes) = PS;
1162 } else {
1163 status = Cache->WriteProc(Context, tmp_buff2, PS, Lba, ReadBytes, 0);
1164 if(!OS_SUCCESS(status)) {
1165 status = WCacheRaiseIoError(Cache, Context, status, Lba, PSs, tmp_buff2, WCACHE_W_OP, NULL);
1166 }
1167 }
1168 } else {
1169 if(Async)
1170 WCacheCompleteAsync__(WContext, STATUS_SUCCESS);
1171 (*ReadBytes) = PS;
1172 return STATUS_SUCCESS;
1173 }
1174
1175 return status;
1176 } // end WCacheUpdatePacket()
1177
1178 /*
1179 WCacheFreePacket() releases storage for all Blocks in packet.
1180 'frame' describes Frame, offset - Block in Frame. offset should be
1181 aligned on Packet size.
1182 Internal routine
1183 */
1184 VOID
1185 WCacheFreePacket(
1186 IN PW_CACHE Cache, // pointer to the Cache Control structure
1187 // IN PVOID Context,
1188 IN ULONG frame, // Frame index
1189 IN PW_CACHE_ENTRY block_array, // Frame
1190 IN ULONG offs, // offset in Frame
1191 IN ULONG PSs // Packet size (in Blocks)
1192 )
1193 {
1194 ULONG i;
1195 // mark as non-cached & free pool
1196 for(i=0; i<PSs; i++, offs++) {
1197 if(WCacheSectorAddr(block_array,offs)) {
1198 WCacheFreeSector(frame, offs);
1199 }
1200 }
1201 } // end WCacheFreePacket()
1202
1203 /*
1204 WCacheUpdatePacketComplete() is called to continue processing of packet
1205 being updated.
1206 In async mode it waits for completion of pre-read requests,
1207 initiates writes, waits for their completion and returns control to
1208 caller.
1209 Internal routine
1210 */
1211 VOID
1212 WCacheUpdatePacketComplete(
1213 IN PW_CACHE Cache, // pointer to the Cache Control structure
1214 IN PVOID Context, // user-supplied context for IO callbacks
1215 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context
1216 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context
1217 IN BOOLEAN FreePacket
1218 )
1219 {
1220 PW_CACHE_ASYNC WContext = (*FirstWContext);
1221 if(!WContext)
1222 return;
1223 PW_CACHE_ASYNC NextWContext;
1224 ULONG PS = Cache->BlockSize << Cache->PacketSizeSh; // packet size (bytes)
1225 ULONG PSs = Cache->PacketSize;
1226 ULONG frame;
1227 lba_t firstLba;
1228
1229 // Walk through all chained blocks and wait
1230 // for completion of read operations.
1231 // Also invoke writes of already prepared packets.
1232 while(WContext) {
1233 if(WContext->Cmd == ASYNC_CMD_UPDATE &&
1234 WContext->State == ASYNC_STATE_READ) {
1235 // wait for async read for update
1236 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL);
1237
1238 WContext->State = ASYNC_STATE_WRITE;
1239 WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1,
1240 PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE);
1241 } else
1242 if(WContext->Cmd == ASYNC_CMD_UPDATE &&
1243 WContext->State == ASYNC_STATE_WRITE_PRE) {
1244 // invoke physical write it the packet is prepared for writing
1245 // by previuous call to WCacheUpdatePacket()
1246 WContext->State = ASYNC_STATE_WRITE;
1247 WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1,
1248 PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE);
1249 WContext->State = ASYNC_STATE_DONE;
1250 } else
1251 if(WContext->Cmd == ASYNC_CMD_READ &&
1252 WContext->State == ASYNC_STATE_READ) {
1253 // wait for async read
1254 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL);
1255 }
1256 WContext = WContext->NextWContext;
1257 }
1258 // Walk through all chained blocks and wait
1259 // and wait for completion of async writes (if any).
1260 // Also free temporary buffers containing already written blocks.
1261 WContext = (*FirstWContext);
1262 while(WContext) {
1263 NextWContext = WContext->NextWContext;
1264 if(WContext->Cmd == ASYNC_CMD_UPDATE &&
1265 WContext->State == ASYNC_STATE_WRITE) {
1266
1267 if(!Cache->Chained)
1268 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL);
1269
1270 frame = WContext->Lba >> Cache->BlocksPerFrameSh;
1271 firstLba = frame << Cache->BlocksPerFrameSh;
1272
1273 if(FreePacket) {
1274 WCacheFreePacket(Cache, frame,
1275 Cache->FrameList[frame].Frame,
1276 WContext->Lba - firstLba, PSs);
1277 }
1278 }
1279 WCacheFreeAsyncEntry(Cache, WContext);
1280 WContext = NextWContext;
1281 }
1282 (*FirstWContext) = NULL;
1283 (*PrevWContext) = NULL;
1284 } // end WCacheUpdatePacketComplete()
1285
1286 /*
1287 WCacheCheckLimits() checks if we've enough free Frame- &
1288 Block-entries under Frame- and Block-limit to feet
1289 requested Blocks.
1290 If there is not enough entries, WCache initiates flush & purge
1291 process to satisfy request.
1292 This is dispatch routine, which calls
1293 WCacheCheckLimitsR() or WCacheCheckLimitsRW() depending on
1294 media type.
1295 Internal routine
1296 */
1297 OSSTATUS
1298 __fastcall
1299 WCacheCheckLimits(
1300 IN PW_CACHE Cache, // pointer to the Cache Control structure
1301 IN PVOID Context, // user-supplied context for IO callbacks
1302 IN lba_t ReqLba, // first LBA to access/cache
1303 IN ULONG BCount // number of Blocks to access/cache
1304 )
1305 {
1306 /* if(!Cache->FrameCount || !Cache->BlockCount) {
1307 ASSERT(!Cache->FrameCount);
1308 ASSERT(!Cache->BlockCount);
1309 if(!Cache->FrameCount)
1310 return STATUS_SUCCESS;
1311 }*/
1312
1313 // check if we have reached Frame or Block limit
1314 if(!Cache->FrameCount && !Cache->BlockCount) {
1315 return STATUS_SUCCESS;
1316 }
1317
1318 // check for empty frames
1319 if(Cache->FrameCount > (Cache->MaxFrames*3)/4) {
1320 ULONG frame;
1321 ULONG i;
1322 for(i=Cache->FrameCount; i>0; i--) {
1323 frame = Cache->CachedFramesList[i-1];
1324 // check if frame is empty
1325 if(!(Cache->FrameList[frame].BlockCount)) {
1326 WCacheRemoveFrame(Cache, Context, frame);
1327 } else {
1328 ASSERT(Cache->FrameList[frame].Frame);
1329 }
1330 }
1331 }
1332
1333 if(!Cache->BlockCount) {
1334 return STATUS_SUCCESS;
1335 }
1336
1337 // invoke media-specific limit-checker
1338 switch(Cache->Mode) {
1339 case WCACHE_MODE_RAM:
1340 return WCacheCheckLimitsRAM(Cache, Context, ReqLba, BCount);
1341 case WCACHE_MODE_ROM:
1342 case WCACHE_MODE_RW:
1343 return WCacheCheckLimitsRW(Cache, Context, ReqLba, BCount);
1344 case WCACHE_MODE_R:
1345 return WCacheCheckLimitsR(Cache, Context, ReqLba, BCount);
1346 }
1347 return STATUS_DRIVER_INTERNAL_ERROR;
1348 } // end WCacheCheckLimits()
1349
1350 /*
1351 WCacheCheckLimitsRW() implements automatic flush and purge of
1352 unused blocks to keep enough free cache entries for newly
1353 read/written blocks for Random Access and ReWritable media
1354 using Read/Modify/Write technology.
1355 See also WCacheCheckLimits()
1356 Internal routine
1357 */
1358 OSSTATUS
1359 __fastcall
1360 WCacheCheckLimitsRW(
1361 IN PW_CACHE Cache, // pointer to the Cache Control structure
1362 IN PVOID Context, // user-supplied context for IO callbacks
1363 IN lba_t ReqLba, // first LBA to access/cache
1364 IN ULONG BCount // number of Blocks to access/cache
1365 )
1366 {
1367 ULONG frame;
1368 lba_t firstLba;
1369 lba_t* List = Cache->CachedBlocksList;
1370 lba_t lastLba;
1371 lba_t Lba;
1372 // PCHAR tmp_buff = Cache->tmp_buff;
1373 ULONG firstPos;
1374 ULONG lastPos;
1375 ULONG BSh = Cache->BlockSizeSh;
1376 ULONG BS = Cache->BlockSize;
1377 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
1378 ULONG PSs = Cache->PacketSize;
1379 ULONG try_count = 0;
1380 PW_CACHE_ENTRY block_array;
1381 OSSTATUS status;
1382 SIZE_T ReadBytes;
1383 ULONG FreeFrameCount = 0;
1384 // PVOID addr;
1385 PW_CACHE_ASYNC FirstWContext = NULL;
1386 PW_CACHE_ASYNC PrevWContext = NULL;
1387 ULONG chain_count = 0;
1388
1389 if(Cache->FrameCount >= Cache->MaxFrames) {
1390 FreeFrameCount = Cache->FramesToKeepFree;
1391 } else
1392 if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
1393 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) {
1394 // we need free space to grow WCache without flushing data
1395 // for some period of time
1396 FreeFrameCount = Cache->FramesToKeepFree;
1397 goto Try_Another_Frame;
1398 }
1399 // remove(flush) some frames
1400 while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) {
1401 Try_Another_Frame:
1402 if(!Cache->FrameCount || !Cache->BlockCount) {
1403 //ASSERT(!Cache->FrameCount);
1404 if(Cache->FrameCount) {
1405 UDFPrint(("ASSERT: Cache->FrameCount = %d, when 0 is expected\n", Cache->FrameCount));
1406 }
1407 ASSERT(!Cache->BlockCount);
1408 if(!Cache->FrameCount)
1409 break;
1410 }
1411
1412 frame = WCacheFindFrameToRelease(Cache);
1413 #if 0
1414 if(Cache->FrameList[frame].WriteCount) {
1415 try_count++;
1416 if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame;
1417 } else {
1418 try_count = 0;
1419 }
1420 #else
1421 if(Cache->FrameList[frame].UpdateCount) {
1422 try_count = MAX_TRIES_FOR_NA;
1423 } else {
1424 try_count = 0;
1425 }
1426 #endif
1427
1428 if(FreeFrameCount)
1429 FreeFrameCount--;
1430
1431 firstLba = frame << Cache->BlocksPerFrameSh;
1432 lastLba = firstLba + Cache->BlocksPerFrame;
1433 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba);
1434 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba);
1435 block_array = Cache->FrameList[frame].Frame;
1436
1437 if(!block_array) {
1438 UDFPrint(("Hmm...\n"));
1439 BrutePoint();
1440 return STATUS_DRIVER_INTERNAL_ERROR;
1441 }
1442
1443 while(firstPos < lastPos) {
1444 // flush packet
1445 Lba = List[firstPos] & ~(PSs-1);
1446
1447 // write packet out or prepare and add to chain (if chained mode enabled)
1448 status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
1449 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE);
1450
1451 if(status != STATUS_PENDING) {
1452 // free memory
1453 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs);
1454 }
1455
1456 Lba += PSs;
1457 while((firstPos < lastPos) && (Lba > List[firstPos])) {
1458 firstPos++;
1459 }
1460 chain_count++;
1461 // write chained packets
1462 if(chain_count >= WCACHE_MAX_CHAIN) {
1463 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
1464 chain_count = 0;
1465 }
1466 }
1467 // remove flushed blocks from all lists
1468 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame);
1469 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame);
1470
1471 WCacheRemoveFrame(Cache, Context, frame);
1472 }
1473
1474 // check if we try to read too much data
1475 if(BCount > Cache->MaxBlocks) {
1476 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext);
1477 return STATUS_INVALID_PARAMETER;
1478 }
1479
1480 // remove(flush) packet
1481 while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
1482 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) {
1483 try_count = 0;
1484 Try_Another_Block:
1485
1486 Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1);
1487 if(Lba == WCACHE_INVALID_LBA) {
1488 ASSERT(!Cache->FrameCount);
1489 ASSERT(!Cache->BlockCount);
1490 break;
1491 }
1492 frame = Lba >> Cache->BlocksPerFrameSh;
1493 firstLba = frame << Cache->BlocksPerFrameSh;
1494 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba);
1495 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs);
1496 block_array = Cache->FrameList[frame].Frame;
1497 if(!block_array) {
1498 // write already prepared blocks to disk and return error
1499 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext);
1500 ASSERT(FALSE);
1501 return STATUS_DRIVER_INTERNAL_ERROR;
1502 }
1503
1504 // write packet out or prepare and add to chain (if chained mode enabled)
1505 status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
1506 Lba, BSh, BS, PS, PSs, &ReadBytes, (try_count >= MAX_TRIES_FOR_NA), ASYNC_STATE_NONE);
1507
1508 if(status == STATUS_RETRY) {
1509 try_count++;
1510 goto Try_Another_Block;
1511 }
1512
1513 // free memory
1514 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs);
1515
1516 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs);
1517 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs);
1518 // check if frame is empty
1519 if(!(Cache->FrameList[frame].BlockCount)) {
1520 WCacheRemoveFrame(Cache, Context, frame);
1521 } else {
1522 ASSERT(Cache->FrameList[frame].Frame);
1523 }
1524 chain_count++;
1525 if(chain_count >= WCACHE_MAX_CHAIN) {
1526 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
1527 chain_count = 0;
1528 }
1529 }
1530 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext);
1531 return STATUS_SUCCESS;
1532 } // end WCacheCheckLimitsRW()
1533
1534 OSSTATUS
1535 __fastcall
1536 WCacheFlushBlocksRAM(
1537 IN PW_CACHE Cache, // pointer to the Cache Control structure
1538 IN PVOID Context, // user-supplied context for IO callbacks
1539 PW_CACHE_ENTRY block_array,
1540 lba_t* List,
1541 ULONG firstPos,
1542 ULONG lastPos,
1543 BOOLEAN Purge
1544 )
1545 {
1546 ULONG frame;
1547 lba_t Lba;
1548 lba_t PrevLba;
1549 lba_t firstLba;
1550 PCHAR tmp_buff = NULL;
1551 ULONG n;
1552 ULONG BSh = Cache->BlockSizeSh;
1553 ULONG BS = Cache->BlockSize;
1554 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
1555 ULONG PSs = Cache->PacketSize;
1556 SIZE_T _WrittenBytes;
1557 OSSTATUS status = STATUS_SUCCESS;
1558
1559 frame = List[firstPos] >> Cache->BlocksPerFrameSh;
1560 firstLba = frame << Cache->BlocksPerFrameSh;
1561
1562 while(firstPos < lastPos) {
1563 // flush blocks
1564 ASSERT(Cache->FrameCount <= Cache->MaxFrames);
1565 Lba = List[firstPos];
1566 if(!WCacheGetModFlag(block_array, Lba - firstLba)) {
1567 // free memory
1568 if(Purge) {
1569 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, 1);
1570 }
1571 firstPos++;
1572 continue;
1573 }
1574 tmp_buff = Cache->tmp_buff;
1575 PrevLba = Lba;
1576 n=1;
1577 while((firstPos+n < lastPos) &&
1578 (List[firstPos+n] == PrevLba+1)) {
1579 PrevLba++;
1580 if(!WCacheGetModFlag(block_array, PrevLba - firstLba))
1581 break;
1582 DbgCopyMemory(tmp_buff + (n << BSh),
1583 (PVOID)WCacheSectorAddr(block_array, PrevLba - firstLba),
1584 BS);
1585 n++;
1586 if(n >= PSs)
1587 break;
1588 }
1589 if(n > 1) {
1590 DbgCopyMemory(tmp_buff,
1591 (PVOID)WCacheSectorAddr(block_array, Lba - firstLba),
1592 BS);
1593 } else {
1594 tmp_buff = (PCHAR)WCacheSectorAddr(block_array, Lba - firstLba);
1595 }
1596 // write sectors out
1597 status = Cache->WriteProc(Context, tmp_buff, n<<BSh, Lba, &_WrittenBytes, 0);
1598 if(!OS_SUCCESS(status)) {
1599 status = WCacheRaiseIoError(Cache, Context, status, Lba, n, tmp_buff, WCACHE_W_OP, NULL);
1600 if(!OS_SUCCESS(status)) {
1601 BrutePoint();
1602 }
1603 }
1604 firstPos += n;
1605 if(Purge) {
1606 // free memory
1607 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, n);
1608 } else {
1609 // clear Modified flag
1610 ULONG i;
1611 Lba -= firstLba;
1612 for(i=0; i<n; i++) {
1613 WCacheClrModFlag(block_array, Lba+i);
1614 }
1615 }
1616 }
1617
1618 return status;
1619 } // end WCacheFlushBlocksRAM()
1620
1621 /*
1622 WCacheCheckLimitsRAM() implements automatic flush and purge of
1623 unused blocks to keep enough free cache entries for newly
1624 read/written blocks for Random Access media.
1625 See also WCacheCheckLimits()
1626 Internal routine
1627 */
1628 OSSTATUS
1629 __fastcall
1630 WCacheCheckLimitsRAM(
1631 IN PW_CACHE Cache, // pointer to the Cache Control structure
1632 IN PVOID Context, // user-supplied context for IO callbacks
1633 IN lba_t ReqLba, // first LBA to access/cache
1634 IN ULONG BCount // number of Blocks to access/cache
1635 )
1636 {
1637 ULONG frame;
1638 lba_t firstLba;
1639 lba_t* List = Cache->CachedBlocksList;
1640 lba_t lastLba;
1641 lba_t Lba;
1642 // PCHAR tmp_buff = Cache->tmp_buff;
1643 ULONG firstPos;
1644 ULONG lastPos;
1645 // ULONG BSh = Cache->BlockSizeSh;
1646 // ULONG BS = Cache->BlockSize;
1647 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
1648 ULONG PSs = Cache->PacketSize;
1649 // ULONG try_count = 0;
1650 PW_CACHE_ENTRY block_array;
1651 // OSSTATUS status;
1652 ULONG FreeFrameCount = 0;
1653 // PVOID addr;
1654
1655 if(Cache->FrameCount >= Cache->MaxFrames) {
1656 FreeFrameCount = Cache->FramesToKeepFree;
1657 } else
1658 if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
1659 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) {
1660 // we need free space to grow WCache without flushing data
1661 // for some period of time
1662 FreeFrameCount = Cache->FramesToKeepFree;
1663 goto Try_Another_Frame;
1664 }
1665 // remove(flush) some frames
1666 while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) {
1667 ASSERT(Cache->FrameCount <= Cache->MaxFrames);
1668 Try_Another_Frame:
1669 if(!Cache->FrameCount || !Cache->BlockCount) {
1670 ASSERT(!Cache->FrameCount);
1671 ASSERT(!Cache->BlockCount);
1672 if(!Cache->FrameCount)
1673 break;
1674 }
1675
1676 frame = WCacheFindFrameToRelease(Cache);
1677 #if 0
1678 if(Cache->FrameList[frame].WriteCount) {
1679 try_count++;
1680 if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame;
1681 } else {
1682 try_count = 0;
1683 }
1684 #else
1685 /*
1686 if(Cache->FrameList[frame].UpdateCount) {
1687 try_count = MAX_TRIES_FOR_NA;
1688 } else {
1689 try_count = 0;
1690 }
1691 */
1692 #endif
1693
1694 if(FreeFrameCount)
1695 FreeFrameCount--;
1696
1697 firstLba = frame << Cache->BlocksPerFrameSh;
1698 lastLba = firstLba + Cache->BlocksPerFrame;
1699 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba);
1700 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba);
1701 block_array = Cache->FrameList[frame].Frame;
1702
1703 if(!block_array) {
1704 UDFPrint(("Hmm...\n"));
1705 BrutePoint();
1706 return STATUS_DRIVER_INTERNAL_ERROR;
1707 }
1708 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE);
1709
1710 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame);
1711 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame);
1712 WCacheRemoveFrame(Cache, Context, frame);
1713 }
1714
1715 // check if we try to read too much data
1716 if(BCount > Cache->MaxBlocks) {
1717 return STATUS_INVALID_PARAMETER;
1718 }
1719
1720 // remove(flush) packet
1721 while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
1722 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) {
1723 // try_count = 0;
1724 //Try_Another_Block:
1725
1726 ASSERT(Cache->FrameCount <= Cache->MaxFrames);
1727 Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1);
1728 if(Lba == WCACHE_INVALID_LBA) {
1729 ASSERT(!Cache->FrameCount);
1730 ASSERT(!Cache->BlockCount);
1731 break;
1732 }
1733 frame = Lba >> Cache->BlocksPerFrameSh;
1734 firstLba = frame << Cache->BlocksPerFrameSh;
1735 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba);
1736 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs);
1737 block_array = Cache->FrameList[frame].Frame;
1738 if(!block_array) {
1739 ASSERT(FALSE);
1740 return STATUS_DRIVER_INTERNAL_ERROR;
1741 }
1742 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE);
1743 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs);
1744 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs);
1745 // check if frame is empty
1746 if(!(Cache->FrameList[frame].BlockCount)) {
1747 WCacheRemoveFrame(Cache, Context, frame);
1748 } else {
1749 ASSERT(Cache->FrameList[frame].Frame);
1750 }
1751 }
1752 return STATUS_SUCCESS;
1753 } // end WCacheCheckLimitsRAM()
1754
1755 /*
1756 WCachePurgeAllRAM()
1757 Internal routine
1758 */
1759 OSSTATUS
1760 __fastcall
1761 WCachePurgeAllRAM(
1762 IN PW_CACHE Cache, // pointer to the Cache Control structure
1763 IN PVOID Context // user-supplied context for IO callbacks
1764 )
1765 {
1766 ULONG frame;
1767 lba_t firstLba;
1768 lba_t* List = Cache->CachedBlocksList;
1769 lba_t lastLba;
1770 ULONG firstPos;
1771 ULONG lastPos;
1772 PW_CACHE_ENTRY block_array;
1773 // OSSTATUS status;
1774
1775 // remove(flush) some frames
1776 while(Cache->FrameCount) {
1777
1778 frame = Cache->CachedFramesList[0];
1779
1780 firstLba = frame << Cache->BlocksPerFrameSh;
1781 lastLba = firstLba + Cache->BlocksPerFrame;
1782 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba);
1783 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba);
1784 block_array = Cache->FrameList[frame].Frame;
1785
1786 if(!block_array) {
1787 UDFPrint(("Hmm...\n"));
1788 BrutePoint();
1789 return STATUS_DRIVER_INTERNAL_ERROR;
1790 }
1791 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE);
1792
1793 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame);
1794 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame);
1795 WCacheRemoveFrame(Cache, Context, frame);
1796 }
1797
1798 ASSERT(!Cache->FrameCount);
1799 ASSERT(!Cache->BlockCount);
1800 return STATUS_SUCCESS;
1801 } // end WCachePurgeAllRAM()
1802
1803 /*
1804 WCacheFlushAllRAM()
1805 Internal routine
1806 */
1807 OSSTATUS
1808 __fastcall
1809 WCacheFlushAllRAM(
1810 IN PW_CACHE Cache, // pointer to the Cache Control structure
1811 IN PVOID Context // user-supplied context for IO callbacks
1812 )
1813 {
1814 ULONG frame;
1815 lba_t firstLba;
1816 lba_t* List = Cache->CachedBlocksList;
1817 lba_t lastLba;
1818 ULONG firstPos;
1819 ULONG lastPos;
1820 PW_CACHE_ENTRY block_array;
1821 // OSSTATUS status;
1822
1823 // flush frames
1824 while(Cache->WriteCount) {
1825
1826 frame = Cache->CachedModifiedBlocksList[0] >> Cache->BlocksPerFrameSh;
1827
1828 firstLba = frame << Cache->BlocksPerFrameSh;
1829 lastLba = firstLba + Cache->BlocksPerFrame;
1830 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba);
1831 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba);
1832 block_array = Cache->FrameList[frame].Frame;
1833
1834 if(!block_array) {
1835 UDFPrint(("Hmm...\n"));
1836 BrutePoint();
1837 return STATUS_DRIVER_INTERNAL_ERROR;
1838 }
1839 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, FALSE);
1840
1841 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame);
1842 }
1843
1844 return STATUS_SUCCESS;
1845 } // end WCacheFlushAllRAM()
1846
1847 /*
1848 WCachePreReadPacket__() reads & caches the whole packet containing
1849 requested LBA. This routine just caches data, it doesn't copy anything
1850 to user buffer.
1851 In general we have no user buffer here... ;)
1852 Public routine
1853 */
1854 OSSTATUS
1855 WCachePreReadPacket__(
1856 IN PW_CACHE Cache, // pointer to the Cache Control structure
1857 IN PVOID Context, // user-supplied context for IO callbacks
1858 IN lba_t Lba // LBA to cache together with whole packet
1859 )
1860 {
1861 ULONG frame;
1862 OSSTATUS status = STATUS_SUCCESS;
1863 PW_CACHE_ENTRY block_array;
1864 ULONG BSh = Cache->BlockSizeSh;
1865 ULONG BS = Cache->BlockSize;
1866 PCHAR addr;
1867 SIZE_T _ReadBytes;
1868 ULONG PS = Cache->PacketSize; // (in blocks)
1869 ULONG BCount = PS;
1870 ULONG i, n, err_count;
1871 BOOLEAN sector_added = FALSE;
1872 ULONG block_type;
1873 BOOLEAN zero = FALSE;//TRUE;
1874 /*
1875 ULONG first_zero=0, last_zero=0;
1876 BOOLEAN count_first_zero = TRUE;
1877 */
1878
1879 Lba &= ~(PS-1);
1880 frame = Lba >> Cache->BlocksPerFrameSh;
1881 i = Lba - (frame << Cache->BlocksPerFrameSh);
1882
1883 // assume successful operation
1884 block_array = Cache->FrameList[frame].Frame;
1885 if(!block_array) {
1886 ASSERT(Cache->FrameCount < Cache->MaxFrames);
1887 block_array = WCacheInitFrame(Cache, Context, frame);
1888 if(!block_array)
1889 return STATUS_INSUFFICIENT_RESOURCES;
1890 }
1891
1892 // skip cached extent (if any)
1893 n=0;
1894 while((n < BCount) &&
1895 (n < Cache->BlocksPerFrame)) {
1896
1897 addr = (PCHAR)WCacheSectorAddr(block_array, i+n);
1898 block_type = Cache->CheckUsedProc(Context, Lba+n);
1899 if(/*WCacheGetBadFlag(block_array,i+n)*/
1900 block_type & WCACHE_BLOCK_BAD) {
1901 // bad packet. no pre-read
1902 return STATUS_DEVICE_DATA_ERROR;
1903 }
1904 if(!(block_type & WCACHE_BLOCK_ZERO)) {
1905 zero = FALSE;
1906 //count_first_zero = FALSE;
1907 //last_zero = 0;
1908 if(!addr) {
1909 // sector is not cached, stop search
1910 break;
1911 }
1912 } else {
1913 /*
1914 if(count_first_zero) {
1915 first_zero++;
1916 }
1917 last_zero++;
1918 */
1919 }
1920 n++;
1921 }
1922 // do nothing if all sectors are already cached
1923 if(n < BCount) {
1924
1925 // read whole packet
1926 if(!zero) {
1927 status = Cache->ReadProc(Context, Cache->tmp_buff_r, PS<<BSh, Lba, &_ReadBytes, PH_TMP_BUFFER);
1928 if(!OS_SUCCESS(status)) {
1929 status = WCacheRaiseIoError(Cache, Context, status, Lba, PS, Cache->tmp_buff_r, WCACHE_R_OP, NULL);
1930 }
1931 } else {
1932 status = STATUS_SUCCESS;
1933 //RtlZeroMemory(Cache->tmp_buff_r, PS<<BSh);
1934 _ReadBytes = PS<<BSh;
1935 }
1936 if(OS_SUCCESS(status)) {
1937 // and now we'll copy them to cache
1938 for(n=0; n<BCount; n++, i++) {
1939 if(WCacheSectorAddr(block_array,i)) {
1940 continue;
1941 }
1942 addr = block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
1943 if(!addr) {
1944 BrutePoint();
1945 break;
1946 }
1947 sector_added = TRUE;
1948 if(!zero) {
1949 DbgCopyMemory(addr, Cache->tmp_buff_r+(n<<BSh), BS);
1950 } else {
1951 RtlZeroMemory(addr, BS);
1952 }
1953 Cache->FrameList[frame].BlockCount++;
1954 }
1955 } else {
1956 // read sectors one by one and copy them to cache
1957 // unreadable sectors will be treated as zero-filled
1958 err_count = 0;
1959 for(n=0; n<BCount; n++, i++) {
1960 if(WCacheSectorAddr(block_array,i)) {
1961 continue;
1962 }
1963 addr = block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
1964 if(!addr) {
1965 BrutePoint();
1966 break;
1967 }
1968 sector_added = TRUE;
1969 status = Cache->ReadProc(Context, Cache->tmp_buff_r, BS, Lba+n, &_ReadBytes, PH_TMP_BUFFER);
1970 if(!OS_SUCCESS(status)) {
1971 status = WCacheRaiseIoError(Cache, Context, status, Lba+n, 1, Cache->tmp_buff_r, WCACHE_R_OP, NULL);
1972 if(!OS_SUCCESS(status)) {
1973 err_count++;
1974 }
1975 }
1976 if(!zero && OS_SUCCESS(status)) {
1977 DbgCopyMemory(addr, Cache->tmp_buff_r, BS);
1978 } else
1979 if(Cache->RememberBB) {
1980 RtlZeroMemory(addr, BS);
1981 /*
1982 if(!OS_SUCCESS(status)) {
1983 WCacheSetBadFlag(block_array,i);
1984 }
1985 */
1986 }
1987 Cache->FrameList[frame].BlockCount++;
1988 if(err_count >= 2) {
1989 break;
1990 }
1991 }
1992 // _ReadBytes = n<<BSh;
1993 }
1994 }
1995
1996 // we know the number of unread sectors if an error occured
1997 // so we can need to update BlockCount
1998 // return number of read bytes
1999 if(sector_added)
2000 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, n);
2001
2002 return status;
2003 } // end WCachePreReadPacket__()
2004
2005 /*
2006 WCacheReadBlocks__() reads data from cache or
2007 read it form media and store in cache.
2008 Public routine
2009 */
2010 OSSTATUS
2011 WCacheReadBlocks__(
2012 IN PW_CACHE Cache, // pointer to the Cache Control structure
2013 IN PVOID Context, // user-supplied context for IO callbacks
2014 IN PCHAR Buffer, // user-supplied buffer for read blocks
2015 IN lba_t Lba, // LBA to start read from
2016 IN ULONG BCount, // number of blocks to be read
2017 OUT PSIZE_T ReadBytes, // user-supplied pointer to ULONG that will
2018 // recieve number of actually read bytes
2019 IN BOOLEAN CachedOnly // specifies that cache is already locked
2020 )
2021 {
2022 ULONG frame;
2023 ULONG i, saved_i, saved_BC = BCount, n;
2024 OSSTATUS status = STATUS_SUCCESS;
2025 PW_CACHE_ENTRY block_array;
2026 ULONG BSh = Cache->BlockSizeSh;
2027 SIZE_T BS = Cache->BlockSize;
2028 PCHAR addr;
2029 ULONG to_read, saved_to_read;
2030 // PCHAR saved_buff = Buffer;
2031 SIZE_T _ReadBytes;
2032 ULONG PS = Cache->PacketSize;
2033 ULONG MaxR = Cache->MaxBytesToRead;
2034 ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n
2035 ULONG d;
2036 ULONG block_type;
2037
2038 WcPrint(("WC:R %x (%x)\n", Lba, BCount));
2039
2040 (*ReadBytes) = 0;
2041 // check if we try to read too much data
2042 if(BCount >= Cache->MaxBlocks) {
2043 i = 0;
2044 if(CachedOnly) {
2045 status = STATUS_INVALID_PARAMETER;
2046 goto EO_WCache_R2;
2047 }
2048 while(TRUE) {
2049 status = WCacheReadBlocks__(Cache, Context, Buffer + (i<<BSh), Lba, PS, &_ReadBytes, FALSE);
2050 (*ReadBytes) += _ReadBytes;
2051 if(!OS_SUCCESS(status) || (BCount <= PS)) break;
2052 BCount -= PS;
2053 Lba += PS;
2054 i += PS;
2055 }
2056 return status;
2057 }
2058 // check if we try to access beyond cached area
2059 if((Lba < Cache->FirstLba) ||
2060 (Lba + BCount - 1 > Cache->LastLba)) {
2061 status = Cache->ReadProc(Context, Buffer, BCount, Lba, ReadBytes, 0);
2062 if(!OS_SUCCESS(status)) {
2063 status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_R_OP, NULL);
2064 }
2065 return status;
2066 }
2067 if(!CachedOnly) {
2068 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2069 }
2070
2071 frame = Lba >> Cache->BlocksPerFrameSh;
2072 i = Lba - (frame << Cache->BlocksPerFrameSh);
2073
2074 if(Cache->CacheWholePacket && (BCount < PS)) {
2075 if(!CachedOnly &&
2076 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba & ~(PS-1), PS*2)) ) {
2077 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2078 return status;
2079 }
2080 } else {
2081 if(!CachedOnly &&
2082 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) {
2083 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2084 return status;
2085 }
2086 }
2087 if(!CachedOnly) {
2088 // convert to shared
2089 // ExConvertExclusiveToSharedLite(&(Cache->WCacheLock));
2090 }
2091
2092 // pre-read packet. It is very useful for
2093 // highly fragmented files
2094 if(Cache->CacheWholePacket && (BCount < PS)) {
2095 // status = WCacheReadBlocks__(Cache, Context, Cache->tmp_buff_r, Lba & (~PacketMask), PS, &_ReadBytes, TRUE);
2096 // we should not perform IO if user requested CachedOnly data
2097 if(!CachedOnly) {
2098 status = WCachePreReadPacket__(Cache, Context, Lba);
2099 }
2100 status = STATUS_SUCCESS;
2101 }
2102
2103 // assume successful operation
2104 block_array = Cache->FrameList[frame].Frame;
2105 if(!block_array) {
2106 ASSERT(!CachedOnly);
2107 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2108 block_array = WCacheInitFrame(Cache, Context, frame);
2109 if(!block_array) {
2110 status = STATUS_INSUFFICIENT_RESOURCES;
2111 goto EO_WCache_R;
2112 }
2113 }
2114
2115 Cache->FrameList[frame].AccessCount++;
2116 while(BCount) {
2117 if(i >= Cache->BlocksPerFrame) {
2118 frame++;
2119 block_array = Cache->FrameList[frame].Frame;
2120 i -= Cache->BlocksPerFrame;
2121 }
2122 if(!block_array) {
2123 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2124 block_array = WCacheInitFrame(Cache, Context, frame);
2125 if(!block_array) {
2126 status = STATUS_INSUFFICIENT_RESOURCES;
2127 goto EO_WCache_R;
2128 }
2129 }
2130 // 'read' cached extent (if any)
2131 // it is just copying
2132 while(BCount &&
2133 (i < Cache->BlocksPerFrame) &&
2134 (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) {
2135 block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount);
2136 if(block_type & WCACHE_BLOCK_BAD) {
2137 //if(WCacheGetBadFlag(block_array,i)) {
2138 status = STATUS_DEVICE_DATA_ERROR;
2139 goto EO_WCache_R;
2140 }
2141 DbgCopyMemory(Buffer, addr, BS);
2142 Buffer += BS;
2143 *ReadBytes += BS;
2144 i++;
2145 BCount--;
2146 }
2147 // read non-cached packet-size-aligned extent (if any)
2148 // now we'll calculate total length & decide if it has enough size
2149 if(!((d = Lba+saved_BC-BCount) & PacketMask) && d ) {
2150 n = 0;
2151 while(BCount &&
2152 (i < Cache->BlocksPerFrame) &&
2153 (!WCacheSectorAddr(block_array, i)) ) {
2154 n++;
2155 BCount--;
2156 }
2157 BCount += n;
2158 n &= ~PacketMask;
2159 if(n>PS) {
2160 if(!OS_SUCCESS(status = Cache->ReadProc(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_ReadBytes, 0))) {
2161 status = WCacheRaiseIoError(Cache, Context, status, Lba+saved_BC-BCount, n, Buffer, WCACHE_R_OP, NULL);
2162 if(!OS_SUCCESS(status)) {
2163 goto EO_WCache_R;
2164 }
2165 }
2166 // WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2167 BCount -= n;
2168 Lba += saved_BC - BCount;
2169 saved_BC = BCount;
2170 i += n;
2171 Buffer += BS*n;
2172 *ReadBytes += BS*n;
2173 }
2174 // } else {
2175 // UDFPrint(("Unaligned\n"));
2176 }
2177 // read non-cached extent (if any)
2178 // firstable, we'll get total number of sectors to read
2179 to_read = 0;
2180 saved_i = i;
2181 d = BCount;
2182 while(d &&
2183 (i < Cache->BlocksPerFrame) &&
2184 (!WCacheSectorAddr(block_array, i)) ) {
2185 i++;
2186 to_read += BS;
2187 d--;
2188 }
2189 // read some not cached sectors
2190 if(to_read) {
2191 i = saved_i;
2192 saved_to_read = to_read;
2193 d = BCount - d;
2194 // split request if necessary
2195 if(saved_to_read > MaxR) {
2196 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2197 n = MaxR >> BSh;
2198 do {
2199 status = Cache->ReadProc(Context, Buffer, MaxR, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0);
2200 *ReadBytes += _ReadBytes;
2201 if(!OS_SUCCESS(status)) {
2202 _ReadBytes &= ~(BS-1);
2203 BCount -= _ReadBytes >> BSh;
2204 saved_to_read -= _ReadBytes;
2205 Buffer += _ReadBytes;
2206 saved_BC = BCount;
2207 goto store_read_data_1;
2208 }
2209 Buffer += MaxR;
2210 saved_to_read -= MaxR;
2211 i += n;
2212 BCount -= n;
2213 d -= n;
2214 } while(saved_to_read > MaxR);
2215 saved_BC = BCount;
2216 }
2217 if(saved_to_read) {
2218 status = Cache->ReadProc(Context, Buffer, saved_to_read, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0);
2219 *ReadBytes += _ReadBytes;
2220 if(!OS_SUCCESS(status)) {
2221 _ReadBytes &= ~(BS-1);
2222 BCount -= _ReadBytes >> BSh;
2223 saved_to_read -= _ReadBytes;
2224 Buffer += _ReadBytes;
2225 goto store_read_data_1;
2226 }
2227 Buffer += saved_to_read;
2228 saved_to_read = 0;
2229 BCount -= d;
2230 }
2231
2232 store_read_data_1:
2233 // and now we'll copy them to cache
2234
2235 //
2236 Buffer -= (to_read - saved_to_read);
2237 i = saved_i;
2238 while(to_read - saved_to_read) {
2239 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
2240 if(!block_array[i].Sector) {
2241 BCount += to_read >> BSh;
2242 status = STATUS_INSUFFICIENT_RESOURCES;
2243 goto EO_WCache_R;
2244 }
2245 DbgCopyMemory(block_array[i].Sector, Buffer, BS);
2246 Cache->FrameList[frame].BlockCount++;
2247 i++;
2248 Buffer += BS;
2249 to_read -= BS;
2250 }
2251 if(!OS_SUCCESS(status))
2252 goto EO_WCache_R;
2253 to_read = 0;
2254 }
2255 }
2256
2257 EO_WCache_R:
2258
2259 // we know the number of unread sectors if an error occured
2260 // so we can need to update BlockCount
2261 // return number of read bytes
2262 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2263 // Cache->FrameList[frame].BlockCount -= BCount;
2264 EO_WCache_R2:
2265 if(!CachedOnly) {
2266 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2267 }
2268
2269 return status;
2270 } // end WCacheReadBlocks__()
2271
2272 /*
2273 WCacheWriteBlocks__() writes data to cache.
2274 Data is written directly to media if:
2275 1) requested block is Packet-aligned
2276 2) requested Lba(s) lays beyond cached area
2277 Public routine
2278 */
2279 OSSTATUS
2280 WCacheWriteBlocks__(
2281 IN PW_CACHE Cache, // pointer to the Cache Control structure
2282 IN PVOID Context, // user-supplied context for IO callbacks
2283 IN PCHAR Buffer, // user-supplied buffer containing data to be written
2284 IN lba_t Lba, // LBA to start write from
2285 IN ULONG BCount, // number of blocks to be written
2286 OUT PSIZE_T WrittenBytes, // user-supplied pointer to ULONG that will
2287 // recieve number of actually written bytes
2288 IN BOOLEAN CachedOnly // specifies that cache is already locked
2289 )
2290 {
2291 ULONG frame;
2292 ULONG i, saved_BC = BCount, n, d;
2293 OSSTATUS status = STATUS_SUCCESS;
2294 PW_CACHE_ENTRY block_array;
2295 ULONG BSh = Cache->BlockSizeSh;
2296 ULONG BS = Cache->BlockSize;
2297 PCHAR addr;
2298 // PCHAR saved_buff = Buffer;
2299 SIZE_T _WrittenBytes;
2300 ULONG PS = Cache->PacketSize;
2301 ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n
2302 ULONG block_type;
2303 // BOOLEAN Aligned = FALSE;
2304
2305 BOOLEAN WriteThrough = FALSE;
2306 lba_t WTh_Lba;
2307 ULONG WTh_BCount;
2308
2309 WcPrint(("WC:W %x (%x)\n", Lba, BCount));
2310
2311 *WrittenBytes = 0;
2312 // UDFPrint(("BCount:%x\n",BCount));
2313 // check if we try to read too much data
2314 if(BCount >= Cache->MaxBlocks) {
2315 i = 0;
2316 if(CachedOnly) {
2317 status = STATUS_INVALID_PARAMETER;
2318 goto EO_WCache_W2;
2319 }
2320 while(TRUE) {
2321 // UDFPrint((" BCount:%x\n",BCount));
2322 status = WCacheWriteBlocks__(Cache, Context, Buffer + (i<<BSh), Lba, min(PS,BCount), &_WrittenBytes, FALSE);
2323 (*WrittenBytes) += _WrittenBytes;
2324 BCount -= PS;
2325 Lba += PS;
2326 i += PS;
2327 if(!OS_SUCCESS(status) || (BCount < PS))
2328 return status;
2329 }
2330 }
2331 // check if we try to access beyond cached area
2332 if((Lba < Cache->FirstLba) ||
2333 (Lba + BCount - 1 > Cache->LastLba)) {
2334 return STATUS_INVALID_PARAMETER;
2335 }
2336 if(!CachedOnly) {
2337 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2338 }
2339
2340 frame = Lba >> Cache->BlocksPerFrameSh;
2341 i = Lba - (frame << Cache->BlocksPerFrameSh);
2342
2343 if(!CachedOnly &&
2344 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) {
2345 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2346 return status;
2347 }
2348
2349 // assume successful operation
2350 block_array = Cache->FrameList[frame].Frame;
2351 if(!block_array) {
2352
2353 if(BCount && !(BCount & (PS-1)) && !(Lba & (PS-1)) &&
2354 (Cache->Mode != WCACHE_MODE_R) &&
2355 (i+BCount <= Cache->BlocksPerFrame) &&
2356 !Cache->NoWriteThrough) {
2357 status = Cache->WriteProc(Context, Buffer, BCount<<BSh, Lba, WrittenBytes, 0);
2358 if(!OS_SUCCESS(status)) {
2359 status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_W_OP, NULL);
2360 }
2361 goto EO_WCache_W2;
2362 }
2363
2364 ASSERT(!CachedOnly);
2365 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2366 block_array = WCacheInitFrame(Cache, Context, frame);
2367 if(!block_array) {
2368 status = STATUS_INSUFFICIENT_RESOURCES;
2369 goto EO_WCache_W;
2370 }
2371 }
2372
2373 if(Cache->Mode == WCACHE_MODE_RAM &&
2374 BCount &&
2375 // !(Lba & (PS-1)) &&
2376 (!(BCount & (PS-1)) || (BCount > PS)) ) {
2377 WriteThrough = TRUE;
2378 WTh_Lba = Lba;
2379 WTh_BCount = BCount;
2380 } else
2381 if(Cache->Mode == WCACHE_MODE_RAM &&
2382 ((Lba & ~PacketMask) != ((Lba+BCount-1) & ~PacketMask))
2383 ) {
2384 WriteThrough = TRUE;
2385 WTh_Lba = Lba & ~PacketMask;
2386 WTh_BCount = PS;
2387 }
2388
2389 Cache->FrameList[frame].UpdateCount++;
2390 // UDFPrint((" BCount:%x\n",BCount));
2391 while(BCount) {
2392 if(i >= Cache->BlocksPerFrame) {
2393 frame++;
2394 block_array = Cache->FrameList[frame].Frame;
2395 i -= Cache->BlocksPerFrame;
2396 }
2397 if(!block_array) {
2398 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2399 block_array = WCacheInitFrame(Cache, Context, frame);
2400 if(!block_array) {
2401 status = STATUS_INSUFFICIENT_RESOURCES;
2402 goto EO_WCache_W;
2403 }
2404 }
2405 // 'write' cached extent (if any)
2406 // it is just copying
2407 while(BCount &&
2408 (i < Cache->BlocksPerFrame) &&
2409 (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) {
2410 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",addr, Buffer, BS, BCount));
2411 block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount);
2412 if(Cache->NoWriteBB &&
2413 /*WCacheGetBadFlag(block_array,i)*/
2414 (block_type & WCACHE_BLOCK_BAD)) {
2415 // bad packet. no cached write
2416 status = STATUS_DEVICE_DATA_ERROR;
2417 goto EO_WCache_W;
2418 }
2419 DbgCopyMemory(addr, Buffer, BS);
2420 WCacheSetModFlag(block_array, i);
2421 Buffer += BS;
2422 *WrittenBytes += BS;
2423 i++;
2424 BCount--;
2425 }
2426 // write non-cached not-aligned extent (if any) till aligned one
2427 while(BCount &&
2428 (i & PacketMask) &&
2429 (Cache->Mode != WCACHE_MODE_R) &&
2430 (i < Cache->BlocksPerFrame) &&
2431 (!WCacheSectorAddr(block_array, i)) ) {
2432 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
2433 if(!block_array[i].Sector) {
2434 status = STATUS_INSUFFICIENT_RESOURCES;
2435 goto EO_WCache_W;
2436 }
2437 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount));
2438 DbgCopyMemory(block_array[i].Sector, Buffer, BS);
2439 WCacheSetModFlag(block_array, i);
2440 i++;
2441 Buffer += BS;
2442 *WrittenBytes += BS;
2443 BCount--;
2444 Cache->FrameList[frame].BlockCount ++;
2445 }
2446 // write non-cached packet-size-aligned extent (if any)
2447 // now we'll calculate total length & decide if has enough size
2448 if(!Cache->NoWriteThrough
2449 &&
2450 ( !(i & PacketMask) ||
2451 ((Cache->Mode == WCACHE_MODE_R) && (BCount >= PS)) )) {
2452 n = 0;
2453 while(BCount &&
2454 (i < Cache->BlocksPerFrame) &&
2455 (!WCacheSectorAddr(block_array, i)) ) {
2456 n++;
2457 BCount--;
2458 }
2459 BCount += n;
2460 n &= ~PacketMask;
2461 // if(!OS_SUCCESS(status = Cache->WriteProcAsync(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_WrittenBytes, FALSE)))
2462 if(n) {
2463 // add previously written data to list
2464 d = saved_BC - BCount;
2465 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, d);
2466 WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d);
2467 Lba += d;
2468 saved_BC = BCount;
2469
2470 while(n) {
2471 if(Cache->Mode == WCACHE_MODE_R)
2472 Cache->UpdateRelocProc(Context, Lba, NULL, PS);
2473 if(!OS_SUCCESS(status = Cache->WriteProc(Context, Buffer, PS<<BSh, Lba, &_WrittenBytes, 0))) {
2474 status = WCacheRaiseIoError(Cache, Context, status, Lba, PS, Buffer, WCACHE_W_OP, NULL);
2475 if(!OS_SUCCESS(status)) {
2476 goto EO_WCache_W;
2477 }
2478 }
2479 BCount -= PS;
2480 Lba += PS;
2481 saved_BC = BCount;
2482 i += PS;
2483 Buffer += PS<<BSh;
2484 *WrittenBytes += PS<<BSh;
2485 n-=PS;
2486 }
2487 }
2488 }
2489 // write non-cached not-aligned extent (if any)
2490 while(BCount &&
2491 (i < Cache->BlocksPerFrame) &&
2492 (!WCacheSectorAddr(block_array, i)) ) {
2493 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
2494 if(!block_array[i].Sector) {
2495 status = STATUS_INSUFFICIENT_RESOURCES;
2496 goto EO_WCache_W;
2497 }
2498 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount));
2499 DbgCopyMemory(block_array[i].Sector, Buffer, BS);
2500 WCacheSetModFlag(block_array, i);
2501 i++;
2502 Buffer += BS;
2503 *WrittenBytes += BS;
2504 BCount--;
2505 Cache->FrameList[frame].BlockCount ++;
2506 }
2507 }
2508
2509 EO_WCache_W:
2510
2511 // we know the number of unread sectors if an error occured
2512 // so we can need to update BlockCount
2513 // return number of read bytes
2514 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2515 WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, saved_BC - BCount);
2516
2517 if(WriteThrough && !BCount) {
2518 ULONG d;
2519 // lba_t lastLba;
2520 ULONG firstPos;
2521 ULONG lastPos;
2522
2523 BCount = WTh_BCount;
2524 Lba = WTh_Lba;
2525 while(BCount) {
2526 frame = Lba >> Cache->BlocksPerFrameSh;
2527 // firstLba = frame << Cache->BlocksPerFrameSh;
2528 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba);
2529 d = min(Lba+BCount, (frame+1) << Cache->BlocksPerFrameSh) - Lba;
2530 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba+d);
2531 block_array = Cache->FrameList[frame].Frame;
2532 if(!block_array) {
2533 ASSERT(FALSE);
2534 BCount -= d;
2535 Lba += d;
2536 continue;
2537 }
2538 status = WCacheFlushBlocksRAM(Cache, Context, block_array, Cache->CachedBlocksList, firstPos, lastPos, FALSE);
2539 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d);
2540 BCount -= d;
2541 Lba += d;
2542 }
2543 }
2544
2545 EO_WCache_W2:
2546
2547 if(!CachedOnly) {
2548 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2549 }
2550 return status;
2551 } // end WCacheWriteBlocks__()
2552
2553 /*
2554 WCacheFlushAll__() copies all data stored in cache to media.
2555 Flushed blocks are kept in cache.
2556 Public routine
2557 */
2558 VOID
2559 WCacheFlushAll__(
2560 IN PW_CACHE Cache, // pointer to the Cache Control structure
2561 IN PVOID Context) // user-supplied context for IO callbacks
2562 {
2563 if(!(Cache->ReadProc)) return;
2564 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2565
2566 switch(Cache->Mode) {
2567 case WCACHE_MODE_RAM:
2568 WCacheFlushAllRAM(Cache, Context);
2569 break;
2570 case WCACHE_MODE_ROM:
2571 case WCACHE_MODE_RW:
2572 WCacheFlushAllRW(Cache, Context);
2573 break;
2574 case WCACHE_MODE_R:
2575 WCachePurgeAllR(Cache, Context);
2576 break;
2577 }
2578
2579 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2580 return;
2581 } // end WCacheFlushAll__()
2582
2583 /*
2584 WCachePurgeAll__() copies all data stored in cache to media.
2585 Flushed blocks are removed cache.
2586 Public routine
2587 */
2588 VOID
2589 WCachePurgeAll__(
2590 IN PW_CACHE Cache, // pointer to the Cache Control structure
2591 IN PVOID Context) // user-supplied context for IO callbacks
2592 {
2593 if(!(Cache->ReadProc)) return;
2594 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2595
2596 switch(Cache->Mode) {
2597 case WCACHE_MODE_RAM:
2598 WCachePurgeAllRAM(Cache, Context);
2599 break;
2600 case WCACHE_MODE_ROM:
2601 case WCACHE_MODE_RW:
2602 WCachePurgeAllRW(Cache, Context);
2603 break;
2604 case WCACHE_MODE_R:
2605 WCachePurgeAllR(Cache, Context);
2606 break;
2607 }
2608
2609 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2610 return;
2611 } // end WCachePurgeAll__()
2612 /*
2613 WCachePurgeAllRW() copies modified blocks from cache to media
2614 and removes them from cache
2615 This routine can be used for RAM, RW and ROM media.
2616 For ROM media blocks are just removed.
2617 Internal routine
2618 */
2619 VOID
2620 __fastcall
2621 WCachePurgeAllRW(
2622 IN PW_CACHE Cache, // pointer to the Cache Control structure
2623 IN PVOID Context) // user-supplied context for IO callbacks
2624 {
2625 ULONG frame;
2626 lba_t firstLba;
2627 lba_t* List = Cache->CachedBlocksList;
2628 lba_t Lba;
2629 // ULONG firstPos;
2630 // ULONG lastPos;
2631 ULONG BSh = Cache->BlockSizeSh;
2632 ULONG BS = Cache->BlockSize;
2633 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
2634 ULONG PSs = Cache->PacketSize;
2635 PW_CACHE_ENTRY block_array;
2636 // OSSTATUS status;
2637 SIZE_T ReadBytes;
2638 PW_CACHE_ASYNC FirstWContext = NULL;
2639 PW_CACHE_ASYNC PrevWContext = NULL;
2640 ULONG chain_count = 0;
2641
2642 if(!(Cache->ReadProc)) return;
2643
2644 while(Cache->BlockCount) {
2645 Lba = List[0] & ~(PSs-1);
2646 frame = Lba >> Cache->BlocksPerFrameSh;
2647 firstLba = frame << Cache->BlocksPerFrameSh;
2648 // firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba);
2649 // lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs);
2650 block_array = Cache->FrameList[frame].Frame;
2651 if(!block_array) {
2652 BrutePoint();
2653 return;
2654 }
2655
2656 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
2657 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE);
2658
2659 // free memory
2660 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs);
2661
2662 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs);
2663 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs);
2664 // check if frame is empty
2665 if(!(Cache->FrameList[frame].BlockCount)) {
2666 WCacheRemoveFrame(Cache, Context, frame);
2667 } else {
2668 ASSERT(Cache->FrameList[frame].Frame);
2669 }
2670 chain_count++;
2671 if(chain_count >= WCACHE_MAX_CHAIN) {
2672 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2673 chain_count = 0;
2674 }
2675 }
2676 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext);
2677 return;
2678 } // end WCachePurgeAllRW()
2679
2680 /*
2681 WCacheFlushAllRW() copies modified blocks from cache to media.
2682 All blocks are not removed from cache.
2683 This routine can be used for RAM, RW and ROM media.
2684 Internal routine
2685 */
2686 VOID
2687 __fastcall
2688 WCacheFlushAllRW(
2689 IN PW_CACHE Cache, // pointer to the Cache Control structure
2690 IN PVOID Context) // user-supplied context for IO callbacks
2691 {
2692 ULONG frame;
2693 lba_t firstLba;
2694 lba_t* List = Cache->CachedModifiedBlocksList;
2695 lba_t Lba;
2696 // ULONG firstPos;
2697 // ULONG lastPos;
2698 ULONG BSh = Cache->BlockSizeSh;
2699 ULONG BS = Cache->BlockSize;
2700 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
2701 ULONG PSs = Cache->PacketSize;
2702 ULONG BFs = Cache->BlocksPerFrameSh;
2703 PW_CACHE_ENTRY block_array;
2704 // OSSTATUS status;
2705 SIZE_T ReadBytes;
2706 PW_CACHE_ASYNC FirstWContext = NULL;
2707 PW_CACHE_ASYNC PrevWContext = NULL;
2708 ULONG i;
2709 ULONG chain_count = 0;
2710
2711 if(!(Cache->ReadProc)) return;
2712
2713 // walk through modified blocks
2714 while(Cache->WriteCount) {
2715 Lba = List[0] & ~(PSs-1);
2716 frame = Lba >> BFs;
2717 firstLba = frame << BFs;
2718 // firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba);
2719 // lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs);
2720 block_array = Cache->FrameList[frame].Frame;
2721 if(!block_array) {
2722 BrutePoint();
2723 continue;;
2724 }
2725 // queue modify request
2726 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
2727 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE);
2728 // clear MODIFIED flag for queued blocks
2729 WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs);
2730 Lba -= firstLba;
2731 for(i=0; i<PSs; i++) {
2732 WCacheClrModFlag(block_array, Lba+i);
2733 }
2734 chain_count++;
2735 // check queue size
2736 if(chain_count >= WCACHE_MAX_CHAIN) {
2737 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2738 chain_count = 0;
2739 }
2740 }
2741 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2742 #ifdef DBG
2743 #if 1
2744 // check consistency
2745 List = Cache->CachedBlocksList;
2746 for(i=0; i<Cache->BlockCount; i++) {
2747 Lba = List[i] /*& ~(PSs-1)*/;
2748 frame = Lba >> Cache->BlocksPerFrameSh;
2749 firstLba = frame << Cache->BlocksPerFrameSh;
2750 block_array = Cache->FrameList[frame].Frame;
2751 if(!block_array) {
2752 BrutePoint();
2753 }
2754 ASSERT(!WCacheGetModFlag(block_array, Lba-firstLba));
2755 }
2756 #endif // 1
2757 #endif // DBG
2758 return;
2759 } // end WCacheFlushAllRW()
2760
2761 /*
2762 WCacheRelease__() frees all allocated memory blocks and
2763 deletes synchronization resources
2764 Public routine
2765 */
2766 VOID
2767 WCacheRelease__(
2768 IN PW_CACHE Cache // pointer to the Cache Control structure
2769 )
2770 {
2771 ULONG i, j, k;
2772 PW_CACHE_ENTRY block_array;
2773
2774 Cache->Tag = 0xDEADCACE;
2775 if(!(Cache->ReadProc)) return;
2776 // ASSERT(Cache->Tag == 0xCAC11E00);
2777 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2778 for(i=0; i<Cache->FrameCount; i++) {
2779 j = Cache->CachedFramesList[i];
2780 block_array = Cache->FrameList[j].Frame;
2781 if(block_array) {
2782 for(k=0; k<Cache->BlocksPerFrame; k++) {
2783 if(WCacheSectorAddr(block_array, k)) {
2784 WCacheFreeSector(j, k);
2785 }
2786 }
2787 MyFreePool__(block_array);
2788 }
2789 }
2790 if(Cache->FrameList)
2791 MyFreePool__(Cache->FrameList);
2792 if(Cache->CachedBlocksList)
2793 MyFreePool__(Cache->CachedBlocksList);
2794 if(Cache->CachedBlocksList)
2795 MyFreePool__(Cache->CachedModifiedBlocksList);
2796 if(Cache->CachedFramesList)
2797 MyFreePool__(Cache->CachedFramesList);
2798 if(Cache->tmp_buff_r)
2799 MyFreePool__(Cache->tmp_buff_r);
2800 if(Cache->CachedFramesList)
2801 MyFreePool__(Cache->tmp_buff);
2802 if(Cache->CachedFramesList)
2803 MyFreePool__(Cache->reloc_tab);
2804 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2805 ExDeleteResourceLite(&(Cache->WCacheLock));
2806 RtlZeroMemory(Cache, sizeof(W_CACHE));
2807 return;
2808 } // end WCacheRelease__()
2809
2810 /*
2811 WCacheIsInitialized__() checks if the pointer supplied points
2812 to initialized cache structure.
2813 Public routine
2814 */
2815 BOOLEAN
2816 WCacheIsInitialized__(
2817 IN PW_CACHE Cache
2818 )
2819 {
2820 return (Cache->ReadProc != NULL);
2821 } // end WCacheIsInitialized__()
2822
2823 OSSTATUS
2824 WCacheFlushBlocksRW(
2825 IN PW_CACHE Cache, // pointer to the Cache Control structure
2826 IN PVOID Context, // user-supplied context for IO callbacks
2827 IN lba_t _Lba, // LBA to start flush from
2828 IN ULONG BCount // number of blocks to be flushed
2829 )
2830 {
2831 ULONG frame;
2832 lba_t firstLba;
2833 lba_t* List = Cache->CachedModifiedBlocksList;
2834 lba_t Lba;
2835 // ULONG firstPos;
2836 // ULONG lastPos;
2837 ULONG BSh = Cache->BlockSizeSh;
2838 ULONG BS = Cache->BlockSize;
2839 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
2840 ULONG PSs = Cache->PacketSize;
2841 ULONG BFs = Cache->BlocksPerFrameSh;
2842 PW_CACHE_ENTRY block_array;
2843 // OSSTATUS status;
2844 SIZE_T ReadBytes;
2845 PW_CACHE_ASYNC FirstWContext = NULL;
2846 PW_CACHE_ASYNC PrevWContext = NULL;
2847 ULONG i;
2848 ULONG chain_count = 0;
2849 lba_t lim;
2850
2851 if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER;
2852
2853 // walk through modified blocks
2854 lim = (_Lba+BCount+PSs-1) & ~(PSs-1);
2855 for(Lba = _Lba & ~(PSs-1);Lba < lim ; Lba += PSs) {
2856 frame = Lba >> BFs;
2857 firstLba = frame << BFs;
2858 // firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba);
2859 // lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs);
2860 block_array = Cache->FrameList[frame].Frame;
2861 if(!block_array) {
2862 // not cached block may be requested for flush
2863 Lba += (1 << BFs) - PSs;
2864 continue;
2865 }
2866 // queue modify request
2867 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba,
2868 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE);
2869 // clear MODIFIED flag for queued blocks
2870 WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs);
2871 Lba -= firstLba;
2872 for(i=0; i<PSs; i++) {
2873 WCacheClrModFlag(block_array, Lba+i);
2874 }
2875 Lba += firstLba;
2876 chain_count++;
2877 // check queue size
2878 if(chain_count >= WCACHE_MAX_CHAIN) {
2879 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2880 chain_count = 0;
2881 }
2882 }
2883 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE);
2884 /*
2885 if(Cache->Mode != WCACHE_MODE_RAM)
2886 return STATUS_SUCCESS;
2887 */
2888
2889 return STATUS_SUCCESS;
2890 } // end WCacheFlushBlocksRW()
2891
2892 /*
2893 WCacheFlushBlocks__() copies specified blocks stored in cache to media.
2894 Flushed blocks are kept in cache.
2895 Public routine
2896 */
2897 OSSTATUS
2898 WCacheFlushBlocks__(
2899 IN PW_CACHE Cache, // pointer to the Cache Control structure
2900 IN PVOID Context, // user-supplied context for IO callbacks
2901 IN lba_t Lba, // LBA to start flush from
2902 IN ULONG BCount // number of blocks to be flushed
2903 )
2904 {
2905 OSSTATUS status;
2906
2907 if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER;
2908 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2909
2910 // check if we try to access beyond cached area
2911 if((Lba < Cache->FirstLba) ||
2912 (Lba+BCount-1 > Cache->LastLba)) {
2913 UDFPrint(("LBA %#x (%x) is beyond cacheable area\n", Lba, BCount));
2914 BrutePoint();
2915 status = STATUS_INVALID_PARAMETER;
2916 goto EO_WCache_F;
2917 }
2918
2919 switch(Cache->Mode) {
2920 case WCACHE_MODE_RAM:
2921 // WCacheFlushBlocksRW(Cache, Context);
2922 // break;
2923 case WCACHE_MODE_ROM:
2924 case WCACHE_MODE_RW:
2925 status = WCacheFlushBlocksRW(Cache, Context, Lba, BCount);
2926 break;
2927 case WCACHE_MODE_R:
2928 status = STATUS_SUCCESS;
2929 break;
2930 }
2931 EO_WCache_F:
2932 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
2933 return status;
2934 } // end WCacheFlushBlocks__()
2935
2936 /*
2937 WCacheDirect__() returns pointer to memory block where
2938 requested block is stored in.
2939 If no #CachedOnly flag specified this routine locks cache,
2940 otherwise it assumes that cache is already locked by previous call
2941 to WCacheStartDirect__().
2942 Cache can be unlocked by WCacheEODirect__().
2943 Using this routine caller can access cached block directly in memory
2944 without Read_to_Tmp and Modify/Write steps.
2945 Public routine
2946 */
2947 OSSTATUS
2948 WCacheDirect__(
2949 IN PW_CACHE Cache, // pointer to the Cache Control structure
2950 IN PVOID Context, // user-supplied context for IO callbacks
2951 IN lba_t Lba, // LBA of block to get pointer to
2952 IN BOOLEAN Modified, // indicates that block will be modified
2953 OUT PCHAR* CachedBlock, // address for pointer to cached block to be stored in
2954 IN BOOLEAN CachedOnly // specifies that cache is already locked
2955 )
2956 {
2957 ULONG frame;
2958 ULONG i;
2959 OSSTATUS status = STATUS_SUCCESS;
2960 PW_CACHE_ENTRY block_array;
2961 ULONG BS = Cache->BlockSize;
2962 PCHAR addr;
2963 SIZE_T _ReadBytes;
2964 ULONG block_type;
2965
2966 WcPrint(("WC:%sD %x (1)\n", Modified ? "W" : "R", Lba));
2967
2968 // lock cache if nececcary
2969 if(!CachedOnly) {
2970 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
2971 }
2972 // check if we try to access beyond cached area
2973 if((Lba < Cache->FirstLba) ||
2974 (Lba > Cache->LastLba)) {
2975 UDFPrint(("LBA %#x is beyond cacheable area\n", Lba));
2976 BrutePoint();
2977 status = STATUS_INVALID_PARAMETER;
2978 goto EO_WCache_D;
2979 }
2980
2981 frame = Lba >> Cache->BlocksPerFrameSh;
2982 i = Lba - (frame << Cache->BlocksPerFrameSh);
2983 // check if we have enough space to store requested block
2984 if(!CachedOnly &&
2985 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, 1))) {
2986 BrutePoint();
2987 goto EO_WCache_D;
2988 }
2989
2990 // small updates are more important
2991 block_array = Cache->FrameList[frame].Frame;
2992 if(Modified) {
2993 Cache->FrameList[frame].UpdateCount+=8;
2994 } else {
2995 Cache->FrameList[frame].AccessCount+=8;
2996 }
2997 if(!block_array) {
2998 ASSERT(Cache->FrameCount < Cache->MaxFrames);
2999 block_array = WCacheInitFrame(Cache, Context, frame);
3000 if(!block_array) {
3001 status = STATUS_INSUFFICIENT_RESOURCES;
3002 goto EO_WCache_D;
3003 }
3004 }
3005 // check if requested block is already cached
3006 if( !(addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) {
3007 // block is not cached
3008 // allocate memory and read block from media
3009 // do not set block_array[i].Sector here, because if media access fails and recursive access to cache
3010 // comes, this block should not be marked as 'cached'
3011 addr = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG);
3012 if(!addr) {
3013 status = STATUS_INSUFFICIENT_RESOURCES;
3014 goto EO_WCache_D;
3015 }
3016 block_type = Cache->CheckUsedProc(Context, Lba);
3017 if(block_type == WCACHE_BLOCK_USED) {
3018 status = Cache->ReadProc(Context, addr, BS, Lba, &_ReadBytes, PH_TMP_BUFFER);
3019 if(Cache->RememberBB) {
3020 if(!OS_SUCCESS(status)) {
3021 RtlZeroMemory(addr, BS);
3022 //WCacheSetBadFlag(block_array,i);
3023 }
3024 }
3025 } else {
3026 if(block_type & WCACHE_BLOCK_BAD) {
3027 DbgFreePool(addr);
3028 addr = NULL;
3029 status = STATUS_DEVICE_DATA_ERROR;
3030 goto EO_WCache_D;
3031 }
3032 if(!(block_type & WCACHE_BLOCK_ZERO)) {
3033 BrutePoint();
3034 }
3035 status = STATUS_SUCCESS;
3036 RtlZeroMemory(addr, BS);
3037 }
3038 // now add pointer to buffer to common storage
3039 block_array[i].Sector = addr;
3040 WCacheInsertItemToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba);
3041 if(Modified) {
3042 WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3043 WCacheSetModFlag(block_array, i);
3044 }
3045 Cache->FrameList[frame].BlockCount ++;
3046 } else {
3047 // block is not cached
3048 // just return pointer
3049 block_type = Cache->CheckUsedProc(Context, Lba);
3050 if(block_type & WCACHE_BLOCK_BAD) {
3051 //if(WCacheGetBadFlag(block_array,i)) {
3052 // bad packet. no pre-read
3053 status = STATUS_DEVICE_DATA_ERROR;
3054 goto EO_WCache_D;
3055 }
3056 #ifndef UDF_CHECK_UTIL
3057 ASSERT(block_type & WCACHE_BLOCK_USED);
3058 #else
3059 if(!(block_type & WCACHE_BLOCK_USED)) {
3060 UDFPrint(("LBA %#x is not marked as used\n", Lba));
3061 }
3062 #endif
3063 if(Modified &&
3064 !WCacheGetModFlag(block_array, i)) {
3065 WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3066 WCacheSetModFlag(block_array, i);
3067 }
3068 }
3069 (*CachedBlock) = addr;
3070
3071 EO_WCache_D:
3072
3073 return status;
3074 } // end WCacheDirect__()
3075
3076 /*
3077 WCacheEODirect__() must be used to unlock cache after calls to
3078 to WCacheStartDirect__().
3079 Public routine
3080 */
3081 OSSTATUS
3082 WCacheEODirect__(
3083 IN PW_CACHE Cache, // pointer to the Cache Control structure
3084 IN PVOID Context // user-supplied context for IO callbacks
3085 )
3086 {
3087 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
3088 return STATUS_SUCCESS;
3089 } // end WCacheEODirect__()
3090
3091 /*
3092 WCacheStartDirect__() locks cache for exclusive use.
3093 Using this routine caller can access cached block directly in memory
3094 without Read_to_Tmp and Modify/Write steps.
3095 See also WCacheDirect__()
3096 Cache can be unlocked by WCacheEODirect__().
3097 Public routine
3098 */
3099 OSSTATUS
3100 WCacheStartDirect__(
3101 IN PW_CACHE Cache, // pointer to the Cache Control structure
3102 IN PVOID Context, // user-supplied context for IO callbacks
3103 IN BOOLEAN Exclusive // lock cache for exclusive use,
3104 // currently must be TRUE.
3105 )
3106 {
3107 if(Exclusive) {
3108 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
3109 } else {
3110 BrutePoint();
3111 ExAcquireResourceSharedLite(&(Cache->WCacheLock), TRUE);
3112 }
3113 return STATUS_SUCCESS;
3114 } // end WCacheStartDirect__()
3115
3116 /*
3117 WCacheIsCached__() checks if requested blocks are immediately available.
3118 Cache must be previously locked for exclusive use with WCacheStartDirect__().
3119 Using this routine caller can access cached block directly in memory
3120 without Read_to_Tmp and Modify/Write steps.
3121 See also WCacheDirect__().
3122 Cache can be unlocked by WCacheEODirect__().
3123 Public routine
3124 */
3125 BOOLEAN
3126 WCacheIsCached__(
3127 IN PW_CACHE Cache, // pointer to the Cache Control structure
3128 IN lba_t Lba, // LBA to start check from
3129 IN ULONG BCount // number of blocks to be checked
3130 )
3131 {
3132 ULONG frame;
3133 ULONG i;
3134 PW_CACHE_ENTRY block_array;
3135
3136 // check if we try to access beyond cached area
3137 if((Lba < Cache->FirstLba) ||
3138 (Lba + BCount - 1 > Cache->LastLba)) {
3139 return FALSE;
3140 }
3141
3142 frame = Lba >> Cache->BlocksPerFrameSh;
3143 i = Lba - (frame << Cache->BlocksPerFrameSh);
3144
3145 block_array = Cache->FrameList[frame].Frame;
3146 if(!block_array) {
3147 return FALSE;
3148 }
3149
3150 while(BCount) {
3151 if(i >= Cache->BlocksPerFrame) {
3152 frame++;
3153 block_array = Cache->FrameList[frame].Frame;
3154 i -= Cache->BlocksPerFrame;
3155 }
3156 if(!block_array) {
3157 return FALSE;
3158 }
3159 // 'read' cached extent (if any)
3160 while(BCount &&
3161 (i < Cache->BlocksPerFrame) &&
3162 WCacheSectorAddr(block_array, i) &&
3163 /*!WCacheGetBadFlag(block_array, i)*/
3164 /*!(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_BAD)*/
3165 TRUE ) {
3166 i++;
3167 BCount--;
3168 Lba++;
3169 }
3170 if(BCount &&
3171 (i < Cache->BlocksPerFrame) /*&&
3172 (!WCacheSectorAddr(block_array, i))*/ ) {
3173 return FALSE;
3174 }
3175 }
3176 return TRUE;
3177 } // end WCacheIsCached__()
3178
3179 /*
3180 WCacheCheckLimitsR() implements automatic flush and purge of
3181 unused blocks to keep enough free cache entries for newly
3182 read/written blocks for WORM media.
3183 See also WCacheCheckLimits()
3184 Internal routine
3185 */
3186 OSSTATUS
3187 __fastcall
3188 WCacheCheckLimitsR(
3189 IN PW_CACHE Cache, // pointer to the Cache Control structure
3190 IN PVOID Context, // user-supplied context for IO callbacks
3191 IN lba_t ReqLba, // first LBA to access/cache
3192 IN ULONG BCount // number of Blocks to access/cache
3193 )
3194 {
3195 ULONG frame;
3196 lba_t firstLba;
3197 lba_t* List = Cache->CachedBlocksList;
3198 lba_t Lba;
3199 PCHAR tmp_buff = Cache->tmp_buff;
3200 ULONG firstPos;
3201 ULONG BSh = Cache->BlockSizeSh;
3202 ULONG BS = Cache->BlockSize;
3203 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
3204 ULONG PSs = Cache->PacketSize;
3205 ULONG i;
3206 PW_CACHE_ENTRY block_array;
3207 BOOLEAN mod;
3208 OSSTATUS status;
3209 SIZE_T ReadBytes;
3210 ULONG MaxReloc = Cache->PacketSize;
3211 PULONG reloc_tab = Cache->reloc_tab;
3212
3213 // check if we try to read too much data
3214 if(BCount > Cache->MaxBlocks) {
3215 return STATUS_INVALID_PARAMETER;
3216 }
3217
3218 // remove(flush) packets from entire frame(s)
3219 while( ((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) +
3220 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) ||
3221 (Cache->FrameCount >= Cache->MaxFrames) ) {
3222
3223 WCCL_retry_1:
3224
3225 Lba = WCacheFindLbaToRelease(Cache);
3226 if(Lba == WCACHE_INVALID_LBA) {
3227 ASSERT(!Cache->FrameCount);
3228 ASSERT(!Cache->BlockCount);
3229 break;
3230 }
3231 frame = Lba >> Cache->BlocksPerFrameSh;
3232 firstLba = frame << Cache->BlocksPerFrameSh;
3233 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba);
3234 block_array = Cache->FrameList[frame].Frame;
3235 if(!block_array) {
3236 return STATUS_DRIVER_INTERNAL_ERROR;
3237 }
3238 // check if modified
3239 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3240 // read/modify/write
3241 if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) {
3242 if(Cache->WriteCount < MaxReloc) goto WCCL_retry_1;
3243 firstPos = WCacheGetSortedListIndex(Cache->WriteCount, Cache->CachedModifiedBlocksList, Lba);
3244 if(!block_array) {
3245 return STATUS_DRIVER_INTERNAL_ERROR;
3246 }
3247 // prepare packet & reloc table
3248 for(i=0; i<MaxReloc; i++) {
3249 Lba = Cache->CachedModifiedBlocksList[firstPos];
3250 frame = Lba >> Cache->BlocksPerFrameSh;
3251 firstLba = frame << Cache->BlocksPerFrameSh;
3252 block_array = Cache->FrameList[frame].Frame;
3253 DbgCopyMemory(tmp_buff + (i << BSh),
3254 (PVOID)WCacheSectorAddr(block_array, Lba-firstLba),
3255 BS);
3256 reloc_tab[i] = Lba;
3257 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3258 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3259 // mark as non-cached & free pool
3260 WCacheFreeSector(frame, Lba-firstLba);
3261 // check if frame is empty
3262 if(!Cache->FrameList[frame].BlockCount) {
3263 WCacheRemoveFrame(Cache, Context, frame);
3264 }
3265 if(firstPos >= Cache->WriteCount) firstPos=0;
3266 }
3267 // write packet
3268 // status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE);
3269 Cache->UpdateRelocProc(Context, NULL, reloc_tab, MaxReloc);
3270 status = Cache->WriteProc(Context, tmp_buff, PS, NULL, &ReadBytes, 0);
3271 if(!OS_SUCCESS(status)) {
3272 status = WCacheRaiseIoError(Cache, Context, status, NULL, PSs, tmp_buff, WCACHE_W_OP, NULL);
3273 }
3274 } else {
3275
3276 if((i = Cache->BlockCount - Cache->WriteCount) > MaxReloc) i = MaxReloc;
3277 // discard blocks
3278 for(; i; i--) {
3279 Lba = List[firstPos];
3280 frame = Lba >> Cache->BlocksPerFrameSh;
3281 firstLba = frame << Cache->BlocksPerFrameSh;
3282 block_array = Cache->FrameList[frame].Frame;
3283
3284 if( (mod = WCacheGetModFlag(block_array, Lba - firstLba)) &&
3285 (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED) )
3286 continue;
3287 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3288 if(mod)
3289 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3290 // mark as non-cached & free pool
3291 WCacheFreeSector(frame, Lba-firstLba);
3292 // check if frame is empty
3293 if(!Cache->FrameList[frame].BlockCount) {
3294 WCacheRemoveFrame(Cache, Context, frame);
3295 }
3296 if(firstPos >= Cache->WriteCount) firstPos=0;
3297 }
3298 }
3299 }
3300 return STATUS_SUCCESS;
3301 } // end WCacheCheckLimitsR()
3302
3303 /*
3304 WCachePurgeAllR() copies modified blocks from cache to media
3305 and removes them from cache
3306 This routine can be used for R media only.
3307 Internal routine
3308 */
3309 VOID
3310 __fastcall
3311 WCachePurgeAllR(
3312 IN PW_CACHE Cache, // pointer to the Cache Control structure
3313 IN PVOID Context) // user-supplied context for IO callbacks
3314 {
3315 ULONG frame;
3316 lba_t firstLba;
3317 lba_t* List = Cache->CachedBlocksList;
3318 lba_t Lba;
3319 PCHAR tmp_buff = Cache->tmp_buff;
3320 ULONG BSh = Cache->BlockSizeSh;
3321 ULONG BS = Cache->BlockSize;
3322 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
3323 // ULONG PSs = Cache->PacketSize;
3324 PW_CACHE_ENTRY block_array;
3325 BOOLEAN mod;
3326 OSSTATUS status;
3327 SIZE_T ReadBytes;
3328 ULONG MaxReloc = Cache->PacketSize;
3329 PULONG reloc_tab = Cache->reloc_tab;
3330 ULONG RelocCount = 0;
3331 BOOLEAN IncompletePacket;
3332 ULONG i=0;
3333 ULONG PacketTail;
3334
3335 while(Cache->WriteCount < Cache->BlockCount) {
3336
3337 Lba = List[i];
3338 frame = Lba >> Cache->BlocksPerFrameSh;
3339 firstLba = frame << Cache->BlocksPerFrameSh;
3340 block_array = Cache->FrameList[frame].Frame;
3341 if(!block_array) {
3342 BrutePoint();
3343 return;
3344 }
3345 // check if modified
3346 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3347 // just discard
3348 if(!mod || !(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) {
3349 // mark as non-cached & free pool
3350 if(WCacheSectorAddr(block_array,Lba-firstLba)) {
3351 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3352 if(mod)
3353 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3354 // mark as non-cached & free pool
3355 WCacheFreeSector(frame, Lba-firstLba);
3356 // check if frame is empty
3357 if(!Cache->FrameList[frame].BlockCount) {
3358 WCacheRemoveFrame(Cache, Context, frame);
3359 }
3360 } else {
3361 BrutePoint();
3362 }
3363 } else {
3364 i++;
3365 }
3366 }
3367
3368 PacketTail = Cache->WriteCount & (MaxReloc-1);
3369 IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE;
3370
3371 // remove(flush) packet
3372 while((Cache->WriteCount > PacketTail) || (Cache->WriteCount && IncompletePacket)) {
3373
3374 Lba = List[0];
3375 frame = Lba >> Cache->BlocksPerFrameSh;
3376 firstLba = frame << Cache->BlocksPerFrameSh;
3377 block_array = Cache->FrameList[frame].Frame;
3378 if(!block_array) {
3379 BrutePoint();
3380 return;
3381 }
3382 // check if modified
3383 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3384 // pack/reloc/write
3385 if(mod) {
3386 DbgCopyMemory(tmp_buff + (RelocCount << BSh),
3387 (PVOID)WCacheSectorAddr(block_array, Lba-firstLba),
3388 BS);
3389 reloc_tab[RelocCount] = Lba;
3390 RelocCount++;
3391 // write packet
3392 if((RelocCount >= MaxReloc) || (Cache->BlockCount == 1)) {
3393 // status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE);
3394 Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount);
3395 status = Cache->WriteProc(Context, tmp_buff, RelocCount<<BSh, NULL, &ReadBytes, 0);
3396 if(!OS_SUCCESS(status)) {
3397 status = WCacheRaiseIoError(Cache, Context, status, NULL, RelocCount, tmp_buff, WCACHE_W_OP, NULL);
3398 }
3399 RelocCount = 0;
3400 }
3401 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3402 } else {
3403 BrutePoint();
3404 }
3405 // mark as non-cached & free pool
3406 if(WCacheSectorAddr(block_array,Lba-firstLba)) {
3407 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3408 // mark as non-cached & free pool
3409 WCacheFreeSector(frame, Lba-firstLba);
3410 // check if frame is empty
3411 if(!Cache->FrameList[frame].BlockCount) {
3412 WCacheRemoveFrame(Cache, Context, frame);
3413 }
3414 } else {
3415 BrutePoint();
3416 }
3417 }
3418 } // end WCachePurgeAllR()
3419
3420 /*
3421 WCacheSetMode__() changes cache operating mode (ROM/R/RW/RAM).
3422 Public routine
3423 */
3424 OSSTATUS
3425 WCacheSetMode__(
3426 IN PW_CACHE Cache, // pointer to the Cache Control structure
3427 IN ULONG Mode // cache mode/media type to be used
3428 )
3429 {
3430 if(Mode > WCACHE_MODE_MAX) return STATUS_INVALID_PARAMETER;
3431 Cache->Mode = Mode;
3432 return STATUS_SUCCESS;
3433 } // end WCacheSetMode__()
3434
3435 /*
3436 WCacheGetMode__() returns cache operating mode (ROM/R/RW/RAM).
3437 Public routine
3438 */
3439 ULONG
3440 WCacheGetMode__(
3441 IN PW_CACHE Cache
3442 )
3443 {
3444 return Cache->Mode;
3445 } // end WCacheGetMode__()
3446
3447 /*
3448 WCacheGetWriteBlockCount__() returns number of modified blocks, those are
3449 not flushed to media. Is usually used to preallocate blocks for
3450 relocation table on WORM (R) media.
3451 Public routine
3452 */
3453 ULONG
3454 WCacheGetWriteBlockCount__(
3455 IN PW_CACHE Cache
3456 )
3457 {
3458 return Cache->WriteCount;
3459 } // end WCacheGetWriteBlockCount__()
3460
3461 /*
3462 WCacheSyncReloc__() builds list of all modified blocks, currently
3463 stored in cache. For each modified block WCacheSyncReloc__() calls
3464 user-supplied callback routine in order to update relocation table
3465 on WORM (R) media.
3466 Public routine
3467 */
3468 VOID
3469 WCacheSyncReloc__(
3470 IN PW_CACHE Cache,
3471 IN PVOID Context)
3472 {
3473 ULONG frame;
3474 lba_t firstLba;
3475 lba_t* List = Cache->CachedBlocksList;
3476 lba_t Lba;
3477 // ULONG BSh = Cache->BlockSizeSh;
3478 // ULONG BS = Cache->BlockSize;
3479 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes)
3480 // ULONG PSs = Cache->PacketSize;
3481 PW_CACHE_ENTRY block_array;
3482 BOOLEAN mod;
3483 ULONG MaxReloc = Cache->PacketSize;
3484 PULONG reloc_tab = Cache->reloc_tab;
3485 ULONG RelocCount = 0;
3486 BOOLEAN IncompletePacket;
3487
3488 IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE;
3489 // enumerate modified blocks
3490 for(ULONG i=0; IncompletePacket && (i<Cache->BlockCount); i++) {
3491
3492 Lba = List[i];
3493 frame = Lba >> Cache->BlocksPerFrameSh;
3494 firstLba = frame << Cache->BlocksPerFrameSh;
3495 block_array = Cache->FrameList[frame].Frame;
3496 if(!block_array) {
3497 return;
3498 }
3499 // check if modified
3500 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3501 // update relocation table for modified sectors
3502 if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) {
3503 reloc_tab[RelocCount] = Lba;
3504 RelocCount++;
3505 if(RelocCount >= Cache->WriteCount) {
3506 Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount);
3507 break;
3508 }
3509 }
3510 }
3511 } // end WCacheSyncReloc__()
3512
3513 /*
3514 WCacheDiscardBlocks__() removes specified blocks from cache.
3515 Blocks are not flushed to media.
3516 Public routine
3517 */
3518 VOID
3519 WCacheDiscardBlocks__(
3520 IN PW_CACHE Cache,
3521 IN PVOID Context,
3522 IN lba_t ReqLba,
3523 IN ULONG BCount
3524 )
3525 {
3526 ULONG frame;
3527 lba_t firstLba;
3528 lba_t* List;
3529 lba_t Lba;
3530 PW_CACHE_ENTRY block_array;
3531 BOOLEAN mod;
3532 ULONG i;
3533
3534 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE);
3535
3536 UDFPrint((" Discard req: %x@%x\n",BCount, ReqLba));
3537
3538 List = Cache->CachedBlocksList;
3539 if(!List) {
3540 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
3541 return;
3542 }
3543 i = WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba);
3544
3545 // enumerate requested blocks
3546 while((List[i] < (ReqLba+BCount)) && (i < Cache->BlockCount)) {
3547
3548 Lba = List[i];
3549 frame = Lba >> Cache->BlocksPerFrameSh;
3550 firstLba = frame << Cache->BlocksPerFrameSh;
3551 block_array = Cache->FrameList[frame].Frame;
3552 if(!block_array) {
3553 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
3554 BrutePoint();
3555 return;
3556 }
3557 // check if modified
3558 mod = WCacheGetModFlag(block_array, Lba - firstLba);
3559 // just discard
3560
3561 // mark as non-cached & free pool
3562 if(WCacheSectorAddr(block_array,Lba-firstLba)) {
3563 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba);
3564 if(mod)
3565 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba);
3566 // mark as non-cached & free pool
3567 WCacheFreeSector(frame, Lba-firstLba);
3568 // check if frame is empty
3569 if(!Cache->FrameList[frame].BlockCount) {
3570 WCacheRemoveFrame(Cache, Context, frame);
3571 } else {
3572 ASSERT(Cache->FrameList[frame].Frame);
3573 }
3574 } else {
3575 // we should never get here !!!
3576 // getting this part of code means that we have
3577 // placed non-cached block in CachedBlocksList
3578 BrutePoint();
3579 }
3580 }
3581 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread());
3582 } // end WCacheDiscardBlocks__()
3583
3584 OSSTATUS
3585 WCacheCompleteAsync__(
3586 IN PVOID WContext,
3587 IN OSSTATUS Status
3588 )
3589 {
3590 PW_CACHE_ASYNC AsyncCtx = (PW_CACHE_ASYNC)WContext;
3591 // PW_CACHE Cache = AsyncCtx->Cache;
3592
3593 AsyncCtx->PhContext.IosbToUse.Status = Status;
3594 KeSetEvent(&(AsyncCtx->PhContext.event), 0, FALSE);
3595
3596 return STATUS_SUCCESS;
3597 } // end WCacheSetMode__()
3598
3599 /*
3600 WCacheDecodeFlags() updates internal BOOLEANs according to Flags
3601 Internal routine
3602 */
3603 OSSTATUS
3604 __fastcall
3605 WCacheDecodeFlags(
3606 IN PW_CACHE Cache, // pointer to the Cache Control structure
3607 IN ULONG Flags // cache mode flags
3608 )
3609 {
3610 //ULONG OldFlags;
3611 if(Flags & ~WCACHE_VALID_FLAGS) {
3612 UDFPrint(("Invalid flags: %x\n", Flags & ~WCACHE_VALID_FLAGS));
3613 return STATUS_INVALID_PARAMETER;
3614 }
3615 Cache->CacheWholePacket = (Flags & WCACHE_CACHE_WHOLE_PACKET) ? TRUE : FALSE;
3616 Cache->DoNotCompare = (Flags & WCACHE_DO_NOT_COMPARE) ? TRUE : FALSE;
3617 Cache->Chained = (Flags & WCACHE_CHAINED_IO) ? TRUE : FALSE;
3618 Cache->RememberBB = (Flags & WCACHE_MARK_BAD_BLOCKS) ? TRUE : FALSE;
3619 if(Cache->RememberBB) {
3620 Cache->NoWriteBB = (Flags & WCACHE_RO_BAD_BLOCKS) ? TRUE : FALSE;
3621 }
3622 Cache->NoWriteThrough = (Flags & WCACHE_NO_WRITE_THROUGH) ? TRUE : FALSE;
3623
3624 Cache->Flags = Flags;
3625
3626 return STATUS_SUCCESS;
3627 }
3628
3629 /*
3630 WCacheChFlags__() changes cache flags.
3631 Public routine
3632 */
3633 ULONG
3634 WCacheChFlags__(
3635 IN PW_CACHE Cache, // pointer to the Cache Control structure
3636 IN ULONG SetFlags, // cache mode/media type to be set
3637 IN ULONG ClrFlags // cache mode/media type to be cleared
3638 )
3639 {
3640 ULONG Flags;
3641
3642 if(SetFlags || ClrFlags) {
3643 Flags = (Cache->Flags & ~ClrFlags) | SetFlags;
3644
3645 if(!OS_SUCCESS(WCacheDecodeFlags(Cache, Flags))) {
3646 return -1;
3647 }
3648 } else {
3649 return Cache->Flags;
3650 }
3651 return Flags;
3652 } // end WCacheSetMode__()