3 * Revision 15.12 1999/03/25 22:05:00 Michiel
4 * fixed deldir related (beta) bug
6 * Revision 15.11 1999/02/22 16:25:30 Michiel
7 * Changes for increasing deldir capacity
9 * Revision 15.10 1998/09/27 11:26:37 Michiel
12 * Revision 15.9 1998/09/03 07:12:14 Michiel
14 * bugfixes 118, 121, 123 and superindexblocks and td64 support
16 * Revision 15.8 1998/04/23 22:27:07 Michiel
17 * FakeCachedRead toegevoegd om munglist check hits te voorkomen
18 * Bug in WriteToFile opgelost: toevoeging CorrectAnodeAc
20 * Revision 15.7 1997/03/03 22:04:04 Michiel
23 * Revision 15.6 1996/03/14 19:32:56 Michiel
24 * Fixed ChangeFileSize bug: had no effect when # blocks remained constant
26 * Revision 15.5 1996/01/03 09:58:36 Michiel
27 * replaced CopyMem() by memcpy()
29 * Revision 15.4 1995/12/21 11:59:31 Michiel
30 * bugfixes: ValidateCache() block flushing and
31 * WriteToFile expensive last block
33 * Revision 15.3 1995/12/21 11:32:44 Michiel
36 * Revision 15.2 1995/12/14 13:24:08 Michiel
39 * Revision 15.1 1995/12/05 15:47:27 Michiel
40 * Rollover files implemented
41 * Restructured: ReadFromObject, WriteToObject etc
44 * Revision 14.4 1995/11/15 15:44:40 Michiel
45 * WriteToFile, ChangeFileSize adapted to postponed op.
47 * Revision 14.3 1995/11/07 14:57:31 Michiel
48 * support for online directory update in WriteToFile and ChangeFileSize
49 * ReservedAreaLock check
51 * Revision 14.2 1995/10/11 23:25:24 Michiel
52 * UpdateSlot added: improved sequential write
54 * Revision 14.1 1995/10/11 22:18:30 Michiel
55 * new data-caching algorithm
57 * Revision 13.2 1995/10/05 11:01:32 Michiel
60 * Revision 13.1 1995/10/03 11:08:55 Michiel
61 * merged with developtree: anodecache
63 * Revision 12.15 1995/09/04 09:57:10 Michiel
64 * mask check now starts at first whole block and includes last block
66 * Revision 12.14 1995/09/01 11:20:15 Michiel
67 * RawRead and RawWrite error handling changed:
68 * on error a retry|cancel requester appears. Retry and
69 * same volumecheck changed. Numsofterrors update added.
71 * Revision 12.13 1995/08/24 13:48:26 Michiel
72 * TD_DiskChange checking enabled
74 * Revision 12.12 1995/08/21 04:25:48 Michiel
75 * better checks for out of memory
77 * Revision 12.11 1995/08/04 04:13:15 Michiel
78 * extra CUTDOWN protection
80 * Revision 12.10 1995/07/21 06:48:51 Michiel
82 * bugfix: MaxTransfer now doesn't have to be multiple of blocksize
84 * Revision 12.9 1995/07/11 17:29:31 Michiel
85 * ErrorMsg () calls use messages.c variables now.
87 * Revision 12.8 1995/07/07 14:39:17 Michiel
90 * Revision 12.7 1995/06/19 09:42:45 Michiel
91 * Rawwrite returns error if softprotect is on
93 * Revision 12.6 1995/06/16 10:00:15 Michiel
94 * using Allec & FreeBufMem
96 * Revision 12.5 1995/06/16 04:06:29 Michiel
97 * No Touch () in write, just MakeBlockDirty
99 * Revision 12.4 1995/05/20 12:12:12 Michiel
100 * Updated messages to reflect Ami-FileLock
104 * Revision 12.3 1995/03/30 11:54:29 Michiel
105 * Write & Setfilesize now set the checknotify flag
107 * Revision 12.2 1995/02/15 16:43:39 Michiel
109 * Using new headers (struct.h & blocks.h)
111 * Revision 12.1 1995/02/02 11:26:11 Michiel
112 * Version number fix. No changes.
114 * Revision 11.8 1995/01/29 07:34:57 Michiel
116 * ReadFromFile, WriteToFile completely rewritten
118 * DataCaching updated
120 * Revision 11.7 1995/01/26 12:20:42 Michiel
123 * Revision 11.6 1995/01/24 17:44:34 Michiel
126 * Revision 11.5 1995/01/24 15:54:20 Michiel
127 * DirectRead, CachedRead etc
129 * Revision 11.4 1995/01/23 16:43:35 Michiel
130 * Directwrite in WriteToFile added
132 * Revision 11.3 1995/01/18 04:29:34 Michiel
133 * Bugfixes. Now ready for beta release.
135 * Revision 11.2 1995/01/15 05:24:44 Michiel
136 * trackdisk specific parts inhibited
138 * Revision 11.1 1995/01/08 16:17:32 Michiel
139 * Compiled (new MODE_BIG version)
141 * Revision 10.4 1994/11/15 18:06:58 Michiel
142 * __USE_SYSBASE moved..
144 * Revision 10.3 1994/10/28 06:06:40 Michiel
145 * uses new listentry field anodenr
147 * Revision 10.2 1994/10/27 11:30:12 Michiel
148 * *** empty log message ***
150 * Revision 10.1 1994/10/24 11:16:28 Michiel
157 #define __USE_SYSBASE
159 #include <exec/types.h>
160 #include <exec/memory.h>
161 #include <exec/devices.h>
163 #include <exec/errors.h>
164 #include <dos/filehandler.h>
174 #include "disk_protos.h"
175 #include "allocation_protos.h"
176 #include "volume_protos.h"
177 #include "directory_protos.h"
178 #include "anodes_protos.h"
179 #include "update_protos.h"
180 #include "checkaccess_protos.h"
182 #define PROFILE_OFF()
185 /**********************************************************************/
187 /**********************************************************************/
190 static UBYTE debugbuf
[120];
192 #define DebugOn debug++
193 #define DebugOff debug=0
194 #define DebugMsg(msg) if(debug) {NormalErrorMsg(msg, NULL);debug=0;}
195 #define DebugMsgNum(msg, num) sprintf(debugbuf, "%s 0x%08lx.", msg, num); \
196 if(debug) {NormalErrorMsg(debugbuf, NULL);debug=0;}
197 #define DebugMsgName(msg, name) sprintf(debugbuf, "%s >%s<.", msg, name); \
198 if(debug) {NormalErrorMsg(debugbuf, NULL);debug=0;}
203 #define DebugMsgNum(msg,num)
204 #define DebugMsgName(msg, name)
207 enum vctype
{read
, write
};
208 static int CheckDataCache(ULONG blocknr
, globaldata
*g
);
209 static int CachedRead(ULONG blocknr
, SIPTR
*error
, globaldata
*g
);
210 static int FakeCachedRead(ULONG blocknr
, SIPTR
*error
, globaldata
*g
);
211 static UBYTE
*CachedReadD(ULONG blknr
, SIPTR
*err
, globaldata
*g
);
212 static int CachedWrite(UBYTE
*data
, ULONG blocknr
, globaldata
*g
);
213 static void ValidateCache(ULONG blocknr
, ULONG numblocks
, enum vctype
, globaldata
*g
);
214 static void UpdateSlot(int slotnr
, globaldata
*g
);
215 static ULONG
ReadFromRollover(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
, SIPTR
*error
, globaldata
*g
);
216 static ULONG
WriteToRollover(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
, SIPTR
*error
, globaldata
*g
);
217 static SFSIZE
SeekInRollover(fileentry_t
*file
, SFSIZE offset
, LONG mode
, SIPTR
*error
, globaldata
*g
);
218 static SFSIZE
ChangeRolloverSize(fileentry_t
*file
, SFSIZE releof
, LONG mode
, SIPTR
*error
, globaldata
*g
);
219 static ULONG
ReadFromFile(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
, SIPTR
*error
, globaldata
*g
);
220 static ULONG
WriteToFile(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
, SIPTR
*error
, globaldata
*g
);
222 /**********************************************************************/
226 /**********************************************************************/
228 ULONG
ReadFromObject(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
229 SIPTR
*error
, globaldata
*g
)
231 if (!CheckReadAccess(file
,error
,g
))
234 /* check anodechain, make if not there */
235 if (!file
->anodechain
)
237 DB(Trace(2,"ReadFromObject","getting anodechain"));
238 if (!(file
->anodechain
= GetAnodeChain(file
->le
.anodenr
, g
)))
240 *error
= ERROR_NO_FREE_STORE
;
246 if (IsRollover(file
->le
.info
))
247 return ReadFromRollover(file
,buffer
,size
,error
,g
);
250 return ReadFromFile(file
,buffer
,size
,error
,g
);
253 ULONG
WriteToObject(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
254 SIPTR
*error
, globaldata
*g
)
256 /* check write access */
257 if (!CheckWriteAccess(file
, error
, g
))
260 /* check anodechain, make if not there */
261 if (!file
->anodechain
)
263 if (!(file
->anodechain
= GetAnodeChain(file
->le
.anodenr
, g
)))
265 *error
= ERROR_NO_FREE_STORE
;
270 /* changing file -> set notify flag */
271 file
->checknotify
= 1;
275 if (IsRollover(file
->le
.info
))
276 return WriteToRollover(file
,buffer
,size
,error
,g
);
279 return WriteToFile(file
,buffer
,size
,error
,g
);
282 SFSIZE
SeekInObject(fileentry_t
*file
, SFSIZE offset
, LONG mode
, SIPTR
*error
,
286 if (!CheckOperateFile(file
,error
,g
))
289 /* check anodechain, make if not there */
290 if (!file
->anodechain
)
292 if (!(file
->anodechain
= GetAnodeChain(file
->le
.anodenr
, g
)))
294 *error
= ERROR_NO_FREE_STORE
;
300 if (IsRollover(file
->le
.info
))
301 return SeekInRollover(file
,offset
,mode
,error
,g
);
304 return SeekInFile(file
,offset
,mode
,error
,g
);
307 SFSIZE
ChangeObjectSize(fileentry_t
*file
, SFSIZE releof
, LONG mode
,
308 SIPTR
*error
, globaldata
*g
)
311 if (!CheckChangeAccess(file
, error
, g
))
314 /* Changing file -> set notify flag */
315 file
->checknotify
= 1;
318 /* check anodechain, make if not there */
319 if (!file
->anodechain
)
321 if (!(file
->anodechain
= GetAnodeChain(file
->le
.anodenr
, g
)))
323 *error
= ERROR_NO_FREE_STORE
;
329 if (IsRollover(file
->le
.info
))
330 return ChangeRolloverSize(file
,releof
,mode
,error
,g
);
333 return ChangeFileSize(file
,releof
,mode
,error
,g
);
338 /**********************************************************************
340 **********************************************************************/
344 /* Read from rollover: at end of file,
347 static ULONG
ReadFromRollover(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
348 SIPTR
*error
, globaldata
*g
)
350 #define direntry_m file->le.info.file.direntry
351 #define filesize_m GetDEFileSize(file->le.info.file.direntry, g)
353 struct extrafields extrafields
;
356 LONG end
, virtualoffset
, virtualend
, t
;
358 DB(Trace(1,"ReadFromRollover","size = %lx offset = %lx\n",size
,file
->offset
));
360 GetExtraFields(direntry_m
,&extrafields
);
362 /* limit access to end of file */
363 virtualoffset
= file
->offset
- extrafields
.rollpointer
;
364 if (virtualoffset
< 0) virtualoffset
+= filesize_m
;
365 virtualend
= virtualoffset
+ size
;
366 virtualend
= min(virtualend
, extrafields
.virtualsize
);
367 end
= virtualend
- virtualoffset
+ file
->offset
;
369 if (end
> filesize_m
)
371 q
= filesize_m
- file
->offset
;
372 if ((read
= ReadFromFile(file
, buffer
, q
, error
, g
)) != q
)
377 SeekInFile(file
, 0, OFFSET_BEGINNING
, error
, g
);
380 q
= end
- file
->offset
;
381 t
= ReadFromFile(file
, buffer
, q
, error
, g
);
393 /* Write to rollover file. First write upto end of rollover. Then
395 * Max virtualsize = filesize-1
397 static ULONG
WriteToRollover(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
398 SIPTR
*error
, globaldata
*g
)
400 #define direntry_m file->le.info.file.direntry
401 #define filesize_m GetDEFileSize(file->le.info.file.direntry, g)
403 struct extrafields extrafields
;
404 struct direntry
*destentry
;
405 union objectinfo directory
;
407 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
410 LONG end
, virtualend
, virtualoffset
, t
;
413 DB(Trace(1,"WriteToRollover","size = %lx offset=%lx, file=%lx\n",size
,file
->offset
,file
));
414 GetExtraFields(direntry_m
,&extrafields
);
415 end
= file
->offset
+ size
;
417 /* new virtual size */
418 virtualoffset
= file
->offset
- extrafields
.rollpointer
;
419 if (virtualoffset
< 0) virtualoffset
+= filesize_m
;
420 virtualend
= virtualoffset
+ size
;
421 if (virtualend
>= extrafields
.virtualsize
)
423 extrafields
.virtualsize
= min(filesize_m
-1, virtualend
);
427 while (end
> filesize_m
)
429 q
= filesize_m
- file
->offset
;
430 t
= WriteToFile(file
, buffer
, q
, error
, g
);
431 if (t
== -1) return (ULONG
)t
;
433 if (t
!= q
) return (ULONG
)written
;
436 SeekInFile(file
, 0, OFFSET_BEGINNING
, error
, g
);
439 q
= end
- file
->offset
;
440 t
= WriteToFile(file
, buffer
, q
, error
, g
);
446 /* change rollpointer etc */
447 if (extend
&& extrafields
.virtualsize
== filesize_m
- 1)
448 extrafields
.rollpointer
= end
+ 1; /* byte PAST eof is offset 0 */
449 destentry
= (struct direntry
*)entrybuffer
;
450 memcpy(destentry
, direntry_m
, direntry_m
->next
);
451 AddExtraFields(destentry
, &extrafields
);
454 if (!GetParent(&file
->le
.info
, &directory
, error
, g
))
457 ChangeDirEntry(file
->le
.info
.file
, destentry
, &directory
, &fi
, g
);
459 return (ULONG
)written
;
465 static SFSIZE
SeekInRollover(fileentry_t
*file
, SFSIZE offset
, LONG mode
, SIPTR
*error
, globaldata
*g
)
467 #define filesize_m GetDEFileSize(file->le.info.file.direntry, g)
468 #define direntry_m file->le.info.file.direntry
470 struct extrafields extrafields
;
471 LONG oldvirtualoffset
, virtualoffset
;
472 ULONG anodeoffset
, blockoffset
;
474 DB(Trace(1,"SeekInRollover","offset = %ld mode=%ld\n",offset
,mode
));
475 GetExtraFields(direntry_m
,&extrafields
);
478 oldvirtualoffset
= file
->offset
- extrafields
.rollpointer
;
479 if (oldvirtualoffset
< 0) oldvirtualoffset
+= filesize_m
;
483 case OFFSET_BEGINNING
:
484 virtualoffset
= offset
;
488 virtualoffset
= extrafields
.virtualsize
+ offset
;
492 virtualoffset
= oldvirtualoffset
+ offset
;
496 *error
= ERROR_SEEK_ERROR
;
500 if ((virtualoffset
> extrafields
.virtualsize
) || virtualoffset
< 0)
502 *error
= ERROR_SEEK_ERROR
;
506 /* calculate real offset */
507 file
->offset
= virtualoffset
+ extrafields
.rollpointer
;
508 if (file
->offset
> filesize_m
)
509 file
->offset
-= filesize_m
;
511 /* calculate new values */
512 anodeoffset
= file
->offset
>> BLOCKSHIFT
;
513 blockoffset
= file
->offset
& (BLOCKSIZE
-1);
514 file
->currnode
= &file
->anodechain
->head
;
515 CorrectAnodeAC(&file
->currnode
, &anodeoffset
, g
);
517 file
->anodeoffset
= anodeoffset
;
518 file
->blockoffset
= blockoffset
;
520 return oldvirtualoffset
;
527 static SFSIZE
ChangeRolloverSize(fileentry_t
*file
, SFSIZE releof
, LONG mode
,
528 SIPTR
*error
, globaldata
*g
)
530 #define filesize_m GetDEFileSize(file->le.info.file.direntry, g)
531 #define direntry_m file->le.info.file.direntry
533 struct extrafields extrafields
;
534 SFSIZE virtualeof
, virtualoffset
;
535 union objectinfo directory
;
537 struct direntry
*destentry
;
538 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
540 DB(Trace(1,"ChangeRolloverSize","offset = %ld mode=%ld\n",releof
,mode
));
541 GetExtraFields(direntry_m
,&extrafields
);
545 case OFFSET_BEGINNING
:
550 virtualeof
= extrafields
.virtualsize
+ releof
;
554 virtualoffset
= file
->offset
- extrafields
.rollpointer
;
555 if (virtualoffset
< 0) virtualoffset
+= filesize_m
;
556 virtualeof
= virtualoffset
+ releof
;
558 default: /* bogus parameter -> ERROR_SEEK_ERROR */
565 *error
= ERROR_SEEK_ERROR
;
569 /* change virtual size */
570 if (virtualeof
>= filesize_m
)
571 extrafields
.virtualsize
= filesize_m
- 1;
573 extrafields
.virtualsize
= virtualeof
;
575 /* we don't update other filehandles or current offset here */
577 /* commit directoryentry changes */
578 destentry
= (struct direntry
*)entrybuffer
;
579 memcpy(destentry
, direntry_m
, direntry_m
->next
);
580 AddExtraFields(destentry
, &extrafields
);
583 if (!GetParent(&file
->le
.info
, &directory
, error
, g
))
586 ChangeDirEntry(file
->le
.info
.file
, destentry
, &directory
, &fi
, g
);
594 #endif /* ROLLOVER */
600 ** Reads 'size' bytes from file to buffer (if not readprotected)
601 ** result: #bytes read; -1 = error; 0 = eof
603 static ULONG
ReadFromFile(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
604 SIPTR
*error
, globaldata
*g
)
606 ULONG anodeoffset
, blockoffset
, blockstoread
;
607 ULONG fullblks
, bytesleft
;
610 UBYTE
*data
= NULL
, *dataptr
;
611 BOOL directread
= FALSE
;
612 struct anodechainnode
*chnode
;
614 struct deldirentry
*dde
;
617 DB(Trace(1,"ReadFromFile","size = %lx offset = %lx\n",size
,file
->offset
));
618 if (!CheckReadAccess(file
, error
, g
))
621 /* correct size and check if zero */
623 if (IsDelFile(file
->le
.info
)) {
624 if (!(dde
= GetDeldirEntryQuick(file
->le
.info
.delfile
.slotnr
, g
)))
626 tfs
= GetDDFileSize(dde
, g
) - file
->offset
;
630 tfs
= GetDEFileSize(file
->le
.info
.file
.direntry
, g
) - file
->offset
;
632 if (!(size
= min(tfs
, size
)))
636 anodeoffset
= file
->anodeoffset
;
637 blockoffset
= file
->blockoffset
;
638 chnode
= file
->currnode
;
639 t
= blockoffset
+ size
;
640 fullblks
= t
>>BLOCKSHIFT
; /* # full blocks */
641 bytesleft
= t
&(BLOCKSIZE
-1); /* # bytes in last incomplete block */
643 /* check mask, both at start and end */
644 t
= (((IPTR
)(buffer
-blockoffset
+BLOCKSIZE
))&~g
->dosenvec
->de_Mask
) ||
645 (((IPTR
)(buffer
+size
-bytesleft
))&~g
->dosenvec
->de_Mask
);
651 * - larger than one block (use 'direct' cached read for just one)
653 if (!t
|| (fullblks
<2*DIRECTSIZE
&& (blockoffset
+size
>BLOCKSIZE
) &&
654 (blockoffset
|| (bytesleft
&&fullblks
<DIRECTSIZE
))))
656 /* full indirect read */
657 blockstoread
= fullblks
+ (bytesleft
>0);
658 if (!(data
= AllocBufmem (blockstoread
<<BLOCKSHIFT
, g
)))
660 *error
= ERROR_NO_FREE_STORE
;
669 blockstoread
= fullblks
;
672 /* read first blockpart */
675 data
= CachedReadD(chnode
->an
.blocknr
+ anodeoffset
, error
, g
);
678 NextBlockAC(&chnode
, &anodeoffset
, g
);
681 t
= BLOCKSIZE
-blockoffset
;
683 memcpy(dataptr
, data
+blockoffset
, t
);
688 bytesleft
= 0; /* single block access */
693 /* read middle part */
694 while (blockstoread
&& !*error
)
696 if ((blockstoread
+ anodeoffset
) >= chnode
->an
.clustersize
)
697 t
= chnode
->an
.clustersize
- anodeoffset
; /* read length */
701 *error
= DiskRead(dataptr
, t
, chnode
->an
.blocknr
+ anodeoffset
, g
);
705 dataptr
+= t
<<BLOCKSHIFT
;
707 CorrectAnodeAC(&chnode
, &anodeoffset
, g
);
711 /* read last block part/ copy read data to buffer */
715 memcpy(buffer
, data
+blockoffset
, size
);
718 data
= CachedReadD(chnode
->an
.blocknr
+anodeoffset
, error
, g
);
720 memcpy(dataptr
, data
, bytesleft
);
728 file
->anodeoffset
+= fullblks
;
729 file
->blockoffset
= (file
->blockoffset
+ size
)&(BLOCKSIZE
-1); // not bytesleft!!
730 CorrectAnodeAC(&file
->currnode
, &file
->anodeoffset
, g
);
731 file
->offset
+= size
;
736 DB(Trace(1,"Read","failed\n"));
747 ** - Copy data in file at current position;
748 ** - Automatic fileextension;
749 ** - Error = bytecount <> opdracht
750 ** - On error no position update
752 ** - Clear Archivebit -> done by Touch()
753 **V- directory protection (amigados does not do this)
755 ** result: num bytes written; DOPUS wants -1 = error;
757 ** Implementation parts
759 ** - Test on writeprotection; yes -> error;
762 ** - Write firstblockpart
763 ** - Write all whole blocks
764 ** - Write last block
765 ** - | Update directory (if no errors)
766 ** | Deextent filesize (if error)
768 static ULONG
WriteToFile(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
769 SIPTR
*error
, globaldata
*g
)
772 ULONG totalblocks
, oldblocksinfile
;
773 FSIZE oldfilesize
, newfileoffset
;
774 ULONG newblocksinfile
, bytestowrite
, blockstofill
;
775 ULONG anodeoffset
, blockoffset
;
776 UBYTE
*data
= NULL
, *dataptr
;
777 BOOL directwrite
= FALSE
;
778 struct anodechainnode
*chnode
;
781 DB(Trace(1,"WriteToFile","size = %lx offset=%lx, file=%lx\n",size
,file
->offset
,file
));
782 /* initialization values */
783 chnode
= file
->currnode
;
784 anodeoffset
= file
->anodeoffset
;
785 blockoffset
= file
->blockoffset
;
786 totalblocks
= (blockoffset
+ size
+ BLOCKSIZE
-1)>>BLOCKSHIFT
; /* total # changed blocks */
787 if (!(bytestowrite
= size
)) /* # bytes to be done */
790 /* filesize extend */
791 oldfilesize
= GetDEFileSize(file
->le
.info
.file
.direntry
, g
);
792 newfileoffset
= file
->offset
+ size
;
794 /* Check if too large (QUAD) or overflowed (ULONG)? */
795 if (newfileoffset
> MAX_FILE_SIZE
|| newfileoffset
< file
->offset
) {
796 *error
= ERROR_DISK_FULL
;
800 oldblocksinfile
= (oldfilesize
+ BLOCKSIZE
-1)>>BLOCKSHIFT
;
801 newblocksinfile
= (newfileoffset
+ BLOCKSIZE
-1)>>BLOCKSHIFT
;
802 if (newblocksinfile
> oldblocksinfile
)
804 t
= newblocksinfile
- oldblocksinfile
;
805 if (!AllocateBlocksAC(file
->anodechain
, t
, &file
->le
.info
.file
, g
))
807 SetDEFileSize(file
->le
.info
.file
.direntry
, oldfilesize
, g
);
808 *error
= ERROR_DISK_FULL
;
812 /* BUG 980422: this CorrectAnodeAC mode because of AllocateBlockAC!! AND
813 * because anodeoffset can be outside last block! (filepointer is
816 CorrectAnodeAC(&chnode
,&anodeoffset
,g
);
819 maskok
= (((IPTR
)(buffer
-blockoffset
+BLOCKSIZE
))&~g
->dosenvec
->de_Mask
) ||
820 (((IPTR
)(buffer
-blockoffset
+(totalblocks
<<BLOCKSHIFT
)))&~g
->dosenvec
->de_Mask
);
827 if (!maskok
|| (totalblocks
<2*DIRECTSIZE
&& (blockoffset
+size
>BLOCKSIZE
*2) &&
828 (blockoffset
|| totalblocks
<DIRECTSIZE
)))
831 /* allocate temporary data buffer */
832 if (!(dataptr
= data
= AllocBufmem(totalblocks
<<BLOCKSHIFT
, g
)))
834 *error
= ERROR_NO_FREE_STORE
;
838 /* first blockpart */
841 *error
= DiskRead(dataptr
, 1, chnode
->an
.blocknr
+ anodeoffset
, g
);
842 bytestowrite
+= blockoffset
;
843 if (bytestowrite
<BLOCKSIZE
)
844 bytestowrite
= BLOCKSIZE
; /* the first could also be the last block */
847 /* copy all 'to be written' to databuffer */
848 memcpy(dataptr
+blockoffset
, buffer
, size
);
856 /* first blockpart */
857 if (blockoffset
|| (totalblocks
==1 && newfileoffset
> oldfilesize
))
859 ULONG fbp
; /* first block part */
864 slotnr
= CachedRead(chnode
->an
.blocknr
+ anodeoffset
, error
, g
);
870 /* for one block no offset growing file */
871 slotnr
= FakeCachedRead(chnode
->an
.blocknr
+ anodeoffset
, error
, g
);
874 /* copy data to cache and mark block as dirty */
875 firstblock
= &g
->dc
.data
[slotnr
<<BLOCKSHIFT
];
876 fbp
= BLOCKSIZE
-blockoffset
;
877 fbp
= min(bytestowrite
, fbp
); /* the first could also be the last block */
878 memcpy(firstblock
+blockoffset
, buffer
, fbp
);
879 MarkDataDirty(slotnr
);
881 NextBlockAC(&chnode
, &anodeoffset
, g
);
888 /* write following blocks. If done, then blockoffset always 0 */
889 if (newfileoffset
> oldfilesize
)
891 blockstofill
= totalblocks
;
892 bytestowrite
= totalblocks
<<BLOCKSHIFT
;
895 blockstofill
= bytestowrite
>>BLOCKSHIFT
;
897 while (blockstofill
&& !*error
)
899 if (blockstofill
+ anodeoffset
>= chnode
->an
.clustersize
)
900 t
= chnode
->an
.clustersize
- anodeoffset
; /* t is # blocks to write now */
904 *error
= DiskWrite(dataptr
, t
, chnode
->an
.blocknr
+ anodeoffset
, g
);
908 dataptr
+= t
<<BLOCKSHIFT
;
909 bytestowrite
-= t
<<BLOCKSHIFT
;
911 CorrectAnodeAC(&chnode
, &anodeoffset
, g
);
915 /* write last block (RAW because cache direct) */
916 if (bytestowrite
&& !*error
)
920 slotnr
= CachedRead(chnode
->an
.blocknr
+ anodeoffset
, error
, g
);
923 lastblock
= &g
->dc
.data
[slotnr
<<BLOCKSHIFT
];
924 memcpy(lastblock
, dataptr
, bytestowrite
);
925 MarkDataDirty(slotnr
);
929 /* free mem for indirect write */
934 file
->anodeoffset
+= (blockoffset
+ size
)>>BLOCKSHIFT
;
935 file
->blockoffset
= (blockoffset
+ size
)&(BLOCKSIZE
-1);
936 CorrectAnodeAC(&file
->currnode
, &file
->anodeoffset
, g
);
937 file
->offset
+= size
;
938 SetDEFileSize(file
->le
.info
.file
.direntry
, max(oldfilesize
, file
->offset
), g
);
939 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
944 if (newblocksinfile
>oldblocksinfile
)
946 /* restore old state of file */
948 SetDEFileSize(file
->le
.info
.file
.direntry
, oldfilesize
, g
);
949 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
950 FreeBlocksAC(file
->anodechain
, newblocksinfile
-oldblocksinfile
, freeanodes
, g
);
952 FreeBlocksAC(file
->anodechain
, newblocksinfile
-oldblocksinfile
, freeanodes
, g
);
953 SetDEFileSize(file
->le
.info
.file
.direntry
, oldfilesize
, g
);
954 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
958 DB(Trace(1,"WriteToFile","failed\n"));
967 ** - set fileposition
968 ** - if wrong position, resultposition unknown and error
969 ** - result = old position to start of file, -1 = error
971 ** - the end of the file is 0 from end
974 SFSIZE
SeekInFile(fileentry_t
*file
, SFSIZE offset
, LONG mode
, SIPTR
*error
, globaldata
*g
)
976 SFSIZE oldoffset
, newoffset
;
977 ULONG anodeoffset
, blockoffset
;
979 struct deldirentry
*delfile
= NULL
;
981 DB(Trace(1,"SeekInFile","offset = %ld mode=%ld\n",offset
,mode
));
982 if (IsDelFile(file
->le
.info
))
983 if (!(delfile
= GetDeldirEntryQuick(file
->le
.info
.delfile
.slotnr
, g
)))
988 oldoffset
= file
->offset
;
991 /* TODO: 32-bit wraparound checks */
995 case OFFSET_BEGINNING
:
1002 newoffset
= GetDDFileSize(delfile
, g
) + offset
;
1005 newoffset
= GetDEFileSize(file
->le
.info
.file
.direntry
, g
) + offset
;
1008 case OFFSET_CURRENT
:
1009 newoffset
= oldoffset
+ offset
;
1013 *error
= ERROR_SEEK_ERROR
;
1018 if ((newoffset
> (delfile
? GetDDFileSize(delfile
, g
) :
1019 GetDEFileSize(file
->le
.info
.file
.direntry
, g
))) || (newoffset
< 0))
1021 if ((newoffset
> GetDEFileSize(file
->le
.info
.file
.direntry
)) || (newoffset
< 0))
1024 *error
= ERROR_SEEK_ERROR
;
1028 /* calculate new values */
1029 anodeoffset
= newoffset
>> BLOCKSHIFT
;
1030 blockoffset
= newoffset
& (BLOCKSIZE
-1);
1031 file
->currnode
= &file
->anodechain
->head
;
1032 CorrectAnodeAC(&file
->currnode
, &anodeoffset
, g
);
1033 /* DiskSeek(anode.blocknr + anodeoffset, g); */
1035 file
->anodeoffset
= anodeoffset
;
1036 file
->blockoffset
= blockoffset
;
1037 file
->offset
= newoffset
;
1042 /* Changes the length of a file
1043 ** Returns new length; -1 if failure
1046 ** 'Seek with extend'
1047 ** change other locks
1050 SFSIZE
ChangeFileSize(fileentry_t
*file
, SFSIZE releof
, LONG mode
, SIPTR
*error
,
1056 ULONG myanode
, oldblocksinfile
, newblocksinfile
;
1060 DB(Trace(1,"ChangeFileSize","offset = %ld mode=%ld\n",releof
,mode
));
1061 if (!CheckChangeAccess(file
, error
, g
))
1064 /* Changing file -> set notify flag */
1065 file
->checknotify
= 1;
1068 /* TODO: 32-bit wraparound checks */
1070 /* calculate new eof (ala 'Seek') */
1073 case OFFSET_BEGINNING
:
1078 abseof
= GetDEFileSize(file
->le
.info
.file
.direntry
, g
) + releof
;
1081 case OFFSET_CURRENT
:
1082 abseof
= file
->offset
+ releof
;
1086 *error
= ERROR_SEEK_ERROR
;
1090 /* < 0 check still needed because QUAD is signed */
1091 if (abseof
< 0 || abseof
> MAX_FILE_SIZE
)
1093 *error
= ERROR_SEEK_ERROR
;
1097 /* change allocation (ala WriteToFile) */
1098 oldfilesize
= GetDEFileSize(file
->le
.info
.file
.direntry
, g
);
1099 oldblocksinfile
= (GetDEFileSize(file
->le
.info
.file
.direntry
, g
) + BLOCKSIZE
-1)>>BLOCKSHIFT
;
1100 newblocksinfile
= (abseof
+BLOCKSIZE
-1)>>BLOCKSHIFT
;
1102 if (newblocksinfile
> oldblocksinfile
)
1104 /* new blocks, 4*allocated anode, dirblock */
1105 t
= newblocksinfile
- oldblocksinfile
;
1106 if (!AllocateBlocksAC(file
->anodechain
, t
, &file
->le
.info
.file
, g
))
1108 SetDEFileSize(file
->le
.info
.file
.direntry
, oldfilesize
, g
);
1109 *error
= ERROR_DISK_FULL
;
1113 /* change directory: in case of allocate this has to be done
1116 SetDEFileSize(file
->le
.info
.file
.direntry
, abseof
, g
);
1117 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
1119 else if (oldblocksinfile
> newblocksinfile
)
1121 /* change directoryentry beforehand (needed for postponed delete but not
1122 * allowed for online updating allocate).
1124 SetDEFileSize(file
->le
.info
.file
.direntry
, abseof
, g
);
1125 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
1127 t
= oldblocksinfile
- newblocksinfile
;
1128 FreeBlocksAC(file
->anodechain
, t
, freeanodes
, g
);
1130 /* PS: there will always be an anode left, since FreeBlocksAC
1131 * doesn't delete the last anode
1136 /* no change in number of blocks, just change directory entry */
1137 SetDEFileSize(file
->le
.info
.file
.direntry
, abseof
, g
);
1138 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
1141 /* change filehandles (including own) */
1142 myanode
= file
->le
.anodenr
;
1143 for (fe
= HeadOf(&g
->currentvolume
->fileentries
); fe
->next
; fe
=fe
->next
)
1145 if (fe
->anodenr
== myanode
)
1147 if (IsFileEntry(fe
) && ((fileentry_t
*)fe
)->offset
>= abseof
)
1148 SeekInFile((fileentry_t
*)fe
, abseof
, OFFSET_BEGINNING
, error
, g
);
1156 /**********************************************************************/
1158 /**********************************************************************/
1160 /* check datacache. return cache slotnr or -1
1163 static int CheckDataCache(ULONG blocknr
, globaldata
*g
)
1167 for (i
= 0; i
< g
->dc
.size
; i
++)
1169 if (g
->dc
.ref
[i
].blocknr
== blocknr
)
1176 /* get block from cache or put it in cache if it wasn't
1177 * there already. return cache slotnr. errors are indicated by 'error'
1180 static int CachedRead(ULONG blocknr
, SIPTR
*error
, globaldata
*g
)
1185 i
= CheckDataCache(blocknr
, g
);
1186 if (i
!= -1) return i
;
1188 if (g
->dc
.ref
[i
].dirty
&& g
->dc
.ref
[i
].blocknr
)
1191 *error
= RawRead(&g
->dc
.data
[i
<<BLOCKSHIFT
], 1, blocknr
, g
);
1192 g
->dc
.roving
= (g
->dc
.roving
+1)&g
->dc
.mask
;
1193 g
->dc
.ref
[i
].dirty
= 0;
1194 g
->dc
.ref
[i
].blocknr
= blocknr
;
1198 static int FakeCachedRead(ULONG blocknr
, SIPTR
*error
, globaldata
*g
)
1203 i
= CheckDataCache(blocknr
, g
);
1204 if (i
!= -1) return i
;
1206 if (g
->dc
.ref
[i
].dirty
&& g
->dc
.ref
[i
].blocknr
)
1209 memset(&g
->dc
.data
[i
<<BLOCKSHIFT
], 0xAA, BLOCKSIZE
);
1210 g
->dc
.roving
= (g
->dc
.roving
+1)&g
->dc
.mask
;
1211 g
->dc
.ref
[i
].dirty
= 0;
1212 g
->dc
.ref
[i
].blocknr
= blocknr
;
1216 static UBYTE
*CachedReadD(ULONG blknr
, SIPTR
*err
, globaldata
*g
)
1220 i
= CachedRead(blknr
,err
,g
);
1224 return &g
->dc
.data
[i
<<BLOCKSHIFT
];
1227 /* write block in cache. if block was already cached,
1228 * overwrite it. return slotnr (never fails).
1230 static int CachedWrite(UBYTE
*data
, ULONG blocknr
, globaldata
*g
)
1234 i
= CheckDataCache(blocknr
, g
);
1238 g
->dc
.roving
= (g
->dc
.roving
+1)&g
->dc
.mask
;
1239 if (g
->dc
.ref
[i
].dirty
&& g
->dc
.ref
[i
].blocknr
)
1242 memcpy(&g
->dc
.data
[i
<<BLOCKSHIFT
], data
, BLOCKSIZE
);
1243 g
->dc
.ref
[i
].dirty
= 1;
1244 g
->dc
.ref
[i
].blocknr
= blocknr
;
1249 /* flush all blocks in datacache (without updating them first).
1251 void FlushDataCache(globaldata
*g
)
1255 for (i
=0; i
<g
->dc
.size
; i
++)
1256 g
->dc
.ref
[i
].blocknr
= 0;
1259 /* write all dirty blocks to disk
1261 void UpdateDataCache(globaldata
*g
)
1265 for (i
=0; i
<g
->dc
.size
; i
++)
1266 if (g
->dc
.ref
[i
].dirty
&& g
->dc
.ref
[i
].blocknr
)
1271 /* update a data cache slot, and any adjacent blocks
1273 static void UpdateSlot(int slotnr
, globaldata
*g
)
1278 blocknr
= g
->dc
.ref
[slotnr
].blocknr
;
1280 /* find out how many adjacent blocks can be written */
1281 for (i
=slotnr
; i
<g
->dc
.size
; i
++)
1283 if (g
->dc
.ref
[i
].blocknr
!= blocknr
++)
1285 g
->dc
.ref
[i
].dirty
= 0;
1289 RawWrite(&g
->dc
.data
[slotnr
<<BLOCKSHIFT
], i
-slotnr
, g
->dc
.ref
[slotnr
].blocknr
, g
);
1292 /* update cache to reflect blocks read to or written
1293 * from disk. to be called before disk is accessed.
1295 static void ValidateCache(ULONG blocknr
, ULONG numblocks
, enum vctype vctype
, globaldata
*g
)
1299 ENTER("ValidateCache");
1300 for (i
=0; i
<g
->dc
.size
; i
++)
1302 if (g
->dc
.ref
[i
].blocknr
>= blocknr
&&
1303 g
->dc
.ref
[i
].blocknr
< blocknr
+ numblocks
)
1307 if (g
->dc
.ref
[i
].dirty
)
1311 g
->dc
.ref
[i
].blocknr
= 0;
1317 /**********************************************************************/
1318 /* DEVICECOMMANDS */
1319 /* DEVICECOMMANDS */
1320 /* DEVICECOMMANDS */
1321 /**********************************************************************/
1326 ** Reads 'blocks' complete blocks in a caller supplied buffer.
1328 ** input : - buffer: buffer for data
1329 ** - blockstoread: number of blocks to read
1330 ** - blocknr: starting block
1332 ** global: - disk is used to get request struct
1334 ** result: errornr, 0=ok
1336 ULONG
DiskRead(UBYTE
*buffer
, ULONG blockstoread
, ULONG blocknr
, globaldata
*g
)
1341 DB(Trace(1, "DiskRead", "%ld blocks from %ld firstblock %ld\n",
1342 (ULONG
)blockstoread
, (ULONG
)blocknr
, g
->firstblock
));
1344 if (blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1349 if (blockstoread
== 1)
1351 slotnr
= CachedRead(blocknr
, &error
, g
);
1352 memcpy(buffer
, &g
->dc
.data
[slotnr
<<BLOCKSHIFT
], BLOCKSIZE
);
1355 ValidateCache(blocknr
, blockstoread
, read
, g
);
1356 return RawRead(buffer
, blockstoread
, blocknr
, g
);
1362 ** Writes 'blocks' complete blocks from a buffer.
1364 ** input : - buffer: the data
1365 ** - blockstowrite: number of blocks to write
1366 ** - blocknr: starting block
1368 ** global: - disk is used to get request struct
1370 ** result: errornr, 0=ok
1372 ULONG
DiskWrite(UBYTE
*buffer
, ULONG blockstowrite
, ULONG blocknr
, globaldata
*g
)
1377 DB(Trace(1, "DiskWrite", "%ld blocks from %ld + %ld\n", blockstowrite
, blocknr
,
1380 if (blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1385 if (blockstowrite
== 1)
1387 CachedWrite(buffer
, blocknr
, g
);
1390 ValidateCache(blocknr
, blockstowrite
, write
, g
);
1391 error
= RawWrite(buffer
, blockstowrite
, blocknr
, g
);
1393 /* cache last block written */
1396 buffer
+= ((blockstowrite
-1)<<BLOCKSHIFT
);
1397 slotnr
= CachedWrite(buffer
, blocknr
+blockstowrite
-1, g
);
1398 g
->dc
.ref
[slotnr
].dirty
= 0; // we just wrote it
1404 * SCSI direct functions
1409 static int DoSCSICommand(UBYTE
*data
, ULONG datalen
, UBYTE
*command
,
1410 UWORD commandlen
, UBYTE direction
, globaldata
*g
)
1412 g
->scsicmd
.scsi_Data
= (UWORD
*)data
;
1413 g
->scsicmd
.scsi_Length
= datalen
;
1414 g
->scsicmd
.scsi_Command
= command
;
1415 g
->scsicmd
.scsi_CmdLength
= commandlen
;
1416 g
->scsicmd
.scsi_Flags
= SCSIF_AUTOSENSE
| direction
; /* SCSIF_READ or SCSIF_WRITE */
1417 g
->scsicmd
.scsi_SenseData
= g
->sense
;
1418 g
->scsicmd
.scsi_SenseLength
= 18;
1419 g
->scsicmd
.scsi_SenseActual
= 0;
1420 g
->scsicmd
.scsi_Status
= 1;
1422 g
->request
->iotd_Req
.io_Length
= sizeof(struct SCSICmd
);
1423 g
->request
->iotd_Req
.io_Data
= (APTR
)&g
->scsicmd
;
1424 g
->request
->iotd_Req
.io_Command
= HD_SCSICMD
;
1425 if (DoIO((struct IORequest
*)g
->request
) != 0)
1428 DebugPutHex("doio", err
);
1429 DebugPutHex("status", g
->scsicmd
.scsi_Status
);
1431 if (g
->scsicmd
.scsi_Status
)
1437 static ULONG
RawRead_DS(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1440 ULONG transfer
, maxtransfer
;
1442 if(blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1445 blocknr
+= g
->firstblock
;
1447 if(!(InPartition(blocknr
) && InPartition(blocknr
+blocks
-1)))
1449 ErrorMsg(AFS_ERROR_READ_OUTSIDE
, NULL
, g
);
1450 return ERROR_SEEK_ERROR
;
1453 /* chop in maxtransfer chunks */
1454 maxtransfer
= g
->maxtransfer
>> BLOCKSHIFT
;
1457 transfer
= min(blocks
,maxtransfer
);
1458 *((UWORD
*)&cmdbuf
[0]) = 0x2800;
1459 *((ULONG
*)&cmdbuf
[2]) = blocknr
;
1460 *((ULONG
*)&cmdbuf
[6]) = transfer
<<8;
1462 if (!DoSCSICommand(buffer
,transfer
<<BLOCKSHIFT
,cmdbuf
,10,SCSIF_READ
,g
))
1466 args
[0] = g
->sense
[2];
1467 args
[1] = blocknr
- g
->firstblock
;
1468 while ((g
->ErrorMsg
)(AFS_ERROR_READ_ERROR
, args
, 2, g
))
1470 if (CheckCurrentVolumeBack(g
))
1473 if (!g
->softprotect
)
1478 if (g
->currentvolume
)
1479 g
->currentvolume
->numsofterrors
++;
1482 buffer
+= transfer
<<BLOCKSHIFT
;
1484 blocknr
+= transfer
;
1491 * VVV Todo: SCSI ErrorNumber in requester
1494 static ULONG
RawWrite_DS(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1497 ULONG transfer
, maxtransfer
;
1499 if(blocknr
== (ULONG
)-1)
1502 blocknr
+= g
->firstblock
;
1505 return ERROR_DISK_WRITE_PROTECTED
;
1507 if (!(InPartition(blocknr
) && InPartition(blocknr
+blocks
-1)))
1509 ErrorMsg (AFS_ERROR_WRITE_OUTSIDE
, NULL
, g
);
1510 return ERROR_SEEK_ERROR
;
1513 /* chop in maxtransfer chunks */
1514 maxtransfer
= g
->maxtransfer
>> BLOCKSHIFT
;
1517 transfer
= min(blocks
,maxtransfer
);
1518 *((UWORD
*)&cmdbuf
[0]) = 0x2a00;
1519 *((ULONG
*)&cmdbuf
[2]) = blocknr
;
1520 *((ULONG
*)&cmdbuf
[6]) = transfer
<<8;
1522 if (!DoSCSICommand(buffer
,blocks
<<BLOCKSHIFT
,cmdbuf
,10,SCSIF_WRITE
,g
))
1526 args
[0] = g
->sense
[2];
1527 args
[1] = blocknr
- g
->firstblock
;
1528 while ((g
->ErrorMsg
)(AFS_ERROR_WRITE_ERROR
, args
, 2, g
))
1530 if (CheckCurrentVolumeBack(g
))
1533 if (!g
->softprotect
)
1538 if (g
->currentvolume
)
1539 g
->currentvolume
->numsofterrors
++;
1542 buffer
+= transfer
<<BLOCKSHIFT
;
1544 blocknr
+= transfer
;
1550 #endif /* SCSI Direct */
1558 /* Geometry MUST be loaded!!
1560 static ULONG
RawRead_TD(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1562 struct IOExtTD
*request
;
1564 ULONG io_length
, io_transfer
, io_offset
, io_actual
= 0, io_startblock
= 0;
1567 DB(Trace(1, "RawRead", "%ld blocks from %ld firstblock %ld\n",
1568 (ULONG
)blocks
, (ULONG
)blocknr
, g
->firstblock
));
1571 if(blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1574 realblocknr
= blocknr
+ g
->firstblock
;
1575 if(!(InPartition(realblocknr
) && InPartition(realblocknr
+blocks
-1)))
1577 ErrorMsg (AFS_ERROR_READ_OUTSIDE
, NULL
, g
);
1578 return ERROR_SEEK_ERROR
;
1581 io_length
= blocks
<< BLOCKSHIFT
;
1582 io_offset
= realblocknr
<< BLOCKSHIFT
;
1584 if (g
->tdmode
>= ACCESS_TD64
) {
1585 // upper 32 bit of offset
1586 io_actual
= realblocknr
>> (32-BLOCKSHIFT
);
1587 io_startblock
= realblocknr
;
1590 while (io_length
> 0)
1592 io_transfer
= min(io_length
, g
->maxtransfer
);
1593 io_transfer
&= ~(BLOCKSIZE
-1);
1594 request
= g
->request
;
1595 request
->iotd_Req
.io_Command
= CMD_READ
;
1596 request
->iotd_Req
.io_Length
= io_transfer
;
1597 request
->iotd_Req
.io_Data
= io_buffer
; // bufmemtype ??
1598 request
->iotd_Req
.io_Offset
= io_offset
;
1599 if (g
->tdmode
>= ACCESS_TD64
) {
1600 request
->iotd_Req
.io_Actual
= io_actual
;
1601 request
->iotd_Req
.io_Command
= g
->tdmode
== ACCESS_NSD
? NSCMD_TD_READ64
: TD_READ64
;
1605 if (DoIO((struct IORequest
*)request
) != 0)
1609 args
[0] = request
->iotd_Req
.io_Error
;
1610 args
[1] = blocknr
; /* should be realblocknr ?? */
1611 while ((g
->ErrorMsg
)(AFS_ERROR_READ_ERROR
, args
, 2, g
))
1613 if (CheckCurrentVolumeBack(g
))
1616 if (!g
->softprotect
)
1621 if (g
->currentvolume
)
1622 g
->currentvolume
->numsofterrors
++;
1623 DB(Trace(1,"RawRead","readerror nr %ld\n", args
[0], args
[1]));
1624 return ERROR_NOT_A_DOS_DISK
;
1627 io_buffer
+= io_transfer
;
1628 io_length
-= io_transfer
;
1629 if (g
->tdmode
>= ACCESS_TD64
) {
1630 io_startblock
+= (io_transfer
>> BLOCKSHIFT
);
1631 io_offset
= io_startblock
<< BLOCKSHIFT
;
1632 io_actual
= io_startblock
>> (32-BLOCKSHIFT
);
1634 io_offset
+= io_transfer
;
1643 static ULONG
TD_Format(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1645 struct IOExtTD
*request
;
1648 DB(Trace(1, "TD_Format", "%ld blocks from %ld + %ld\n", blocks
, blocknr
,
1652 if (blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1655 realblocknr
= blocknr
+ g
->firstblock
;
1656 if(!InPartition(realblocknr
))
1658 ErrorMsg (AFS_ERROR_WRITE_OUTSIDE
, NULL
, g
);
1659 return ERROR_SEEK_ERROR
;
1662 request
= g
->request
;
1663 request
->iotd_Req
.io_Command
= TD_FORMAT
;
1664 request
->iotd_Req
.io_Length
= blocks
*BLOCKSIZE
;
1665 request
->iotd_Req
.io_Data
= buffer
; // bufmemtype ??
1666 request
->iotd_Req
.io_Offset
= realblocknr
*BLOCKSIZE
;
1668 if(DoIO((struct IORequest
*)request
) != NULL
)
1672 args
[0] = request
->iotd_Req
.io_Error
;
1673 args
[1] = blocknr
; /* should be realblocknr?? */
1674 while ((g
->ErrorMsg
)(AFS_ERROR_WRITE_ERROR
, args
, 2, g
))
1676 if (CheckCurrentVolumeBack(g
))
1679 if (!g
->softprotect
)
1684 if (g
->currentvolume
)
1685 g
->currentvolume
->numsofterrors
++;
1686 DB(Trace(1,"TD_Format","writeerror nr %d\n", args
[0], args
[1]));
1687 return ERROR_NOT_A_DOS_DISK
;
1693 #endif /* TRACKDISK */
1696 static ULONG
RawWrite_TD(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1698 struct IOExtTD
*request
;
1700 ULONG io_length
, io_transfer
, io_offset
, io_actual
= 0, io_startblock
= 0;
1703 DB(Trace(1, "RawWrite", "%ld blocks from %ld + %ld\n", blocks
, blocknr
,
1707 if(blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1711 return ERROR_DISK_WRITE_PROTECTED
;
1713 realblocknr
= blocknr
+ g
->firstblock
;
1714 if (!(InPartition(realblocknr
) && InPartition(realblocknr
+blocks
-1)))
1716 ErrorMsg (AFS_ERROR_WRITE_OUTSIDE
, NULL
, g
);
1717 return ERROR_SEEK_ERROR
;
1720 io_length
= blocks
<< BLOCKSHIFT
;
1721 io_offset
= realblocknr
<< BLOCKSHIFT
;
1723 if (g
->tdmode
>= ACCESS_TD64
) {
1724 // upper 32 bit of offset
1725 io_actual
= realblocknr
>> (32 - BLOCKSHIFT
);
1726 io_startblock
= realblocknr
;
1729 while(io_length
> 0)
1731 io_transfer
= min(io_length
, g
->maxtransfer
);
1732 io_transfer
&= ~(BLOCKSIZE
-1);
1733 request
= g
->request
;
1734 request
->iotd_Req
.io_Command
= CMD_WRITE
;
1735 request
->iotd_Req
.io_Length
= io_transfer
;
1736 request
->iotd_Req
.io_Data
= io_buffer
; // bufmemtype ??
1737 request
->iotd_Req
.io_Offset
= io_offset
;
1738 if (g
->tdmode
>= ACCESS_TD64
) {
1739 request
->iotd_Req
.io_Actual
= io_actual
;
1740 request
->iotd_Req
.io_Command
= g
->tdmode
== ACCESS_NSD
? NSCMD_TD_WRITE64
: TD_WRITE64
;
1744 if (DoIO((struct IORequest
*)request
) != 0)
1748 args
[0] = request
->iotd_Req
.io_Error
;
1749 args
[1] = blocknr
; /* should be realblocknr?? */
1750 while ((g
->ErrorMsg
)(AFS_ERROR_WRITE_ERROR
, args
, 2, g
))
1752 if (CheckCurrentVolumeBack(g
))
1755 if (!g
->softprotect
)
1760 if (g
->currentvolume
)
1761 g
->currentvolume
->numsofterrors
++;
1762 DB(Trace(1,"RawWrite","writeerror nr %d\n", args
[0], args
[1]));
1763 return ERROR_NOT_A_DOS_DISK
;
1766 io_buffer
+= io_transfer
;
1767 io_length
-= io_transfer
;
1768 if (g
->tdmode
>= ACCESS_TD64
) {
1769 io_startblock
+= (io_transfer
>> BLOCKSHIFT
);
1770 io_offset
= io_startblock
<< BLOCKSHIFT
;
1771 io_actual
= io_startblock
>> (32-BLOCKSHIFT
);
1773 io_offset
+= io_transfer
;
1782 ULONG
RawRead2(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1784 #if (TRACKDISK || TD64 || NSD) && SCSIDIRECT
1785 if (g
->tdmode
== ACCESS_DS
)
1786 return RawRead_DS(buffer
, blocks
, blocknr
, g
);
1788 return RawRead_TD(buffer
, blocks
, blocknr
, g
);
1790 return RawRead_DS(buffer
, blocks
, blocknr
, g
);
1792 return RawRead_TD(buffer
, blocks
, blocknr
, g
);
1796 ULONG
RawRead(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1798 ULONG err
= RawRead2(buffer
, blocks
, blocknr
, g
);
1800 ULONG args
[4] = { (ULONG
)buffer
, blocks
, blocknr
, err
};
1801 ErrorMsg ("RawRead(%lX, %ld, %ld) failed with error %ld", args
, g
);
1806 ULONG
RawWrite2(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1808 #if (TRACKDISK || TD64 || NSD) && SCSIDIRECT
1809 if (g
->tdmode
== ACCESS_DS
)
1810 return RawWrite_DS(buffer
, blocks
, blocknr
, g
);
1812 return RawWrite_TD(buffer
, blocks
, blocknr
, g
);
1814 return RawWrite_DS(buffer
, blocks
, blocknr
, g
);
1816 return RawWrite_TD(buffer
, blocks
, blocknr
, g
);
1820 ULONG
RawWrite(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1822 ULONG err
= RawWrite2(buffer
, blocks
, blocknr
, g
);
1824 ULONG args
[4] = { (ULONG
)buffer
, blocks
, blocknr
, err
};
1825 ErrorMsg ("RawWrite(%lX, %ld, %ld) failed with error %ld", args
, g
);
1833 static UBYTE ACCESS_DEBUG1
[] = "%s:%ld\nfirstblock=%ld\nlastblock=%ld\nblockshift=%ld\nblocksize=%ld\ninside4G=%ld";
1834 static UBYTE ACCESS_DEBUG2
[] = "Test %ld = %ld";
1835 static UBYTE ACCESS_DEBUG3
[] = "SCSI Read Capacity = %ld, Lastblock = %ld";
1838 static void fillbuffer(UBYTE
*buffer
, UBYTE data
, globaldata
*g
)
1840 memset (buffer
, data
+ 1, BLOCKSIZE
);
1842 /* Check if at least one byte has changed */
1843 static BOOL
testbuffer(UBYTE
*buffer
, UBYTE data
, globaldata
*g
)
1847 for (cnt
= 0; cnt
< BLOCKSIZE
; cnt
++) {
1848 if (buffer
[cnt
] != data
+ 1)
1855 static BOOL
testread_ds2(UBYTE
*buffer
, globaldata
*g
)
1861 DebugPutStr("testread_ds\n");
1864 for (cnt
= 0; cnt
< 2; cnt
++) {
1867 fillbuffer(buffer
, 0xfe, g
);
1869 *((UWORD
*)&cmdbuf
[0]) = 0x2500;
1870 *((ULONG
*)&cmdbuf
[2]) = 0;
1871 *((ULONG
*)&cmdbuf
[6]) = 0;
1872 if (!DoSCSICommand(buffer
, 8, cmdbuf
, 10, SCSIF_READ
, g
)) {
1874 DebugPutStr("DoSCSICommand Read Capacity failed\n");
1878 capacity
= *((ULONG
*)buffer
);
1883 args
[1] = g
->lastblock
;
1884 g
->ErrorMsg
= _NormalErrorMsg
;
1885 (g
->ErrorMsg
)(ACCESS_DEBUG3
, args
, 1, g
);
1888 if (g
->lastblock
> capacity
) {
1890 DebugPutStr("DoSCSICommand capacity smaller than last block\n");
1894 fillbuffer(buffer
, cnt
, g
);
1896 *((UWORD
*)&cmdbuf
[0]) = 0x2800;
1897 *((ULONG
*)&cmdbuf
[2]) = g
->lastblock
;
1898 *((ULONG
*)&cmdbuf
[6]) = 1 << 8;
1899 if (!DoSCSICommand(buffer
, 1 << BLOCKSHIFT
, cmdbuf
, 10, SCSIF_READ
, g
)) {
1901 DebugPutStr("DoSCSICommand Read(10) failed\n");
1905 if (testbuffer(buffer
, cnt
, g
)) {
1907 DebugPutStr("ok\n");
1913 DebugPutStr("testbuffer fail\n");
1919 static BOOL
testread_ds(UBYTE
*buffer
, globaldata
*g
)
1923 ok
= testread_ds2(buffer
, g
);
1926 args
[0] = g
->tdmode
;
1928 g
->ErrorMsg
= _NormalErrorMsg
;
1929 (g
->ErrorMsg
)(ACCESS_DEBUG2
, args
, 1, g
);
1934 static BOOL
testread_td2(UBYTE
*buffer
, globaldata
*g
)
1936 struct IOExtTD
*io
= g
->request
;
1940 if (g
->tdmode
== ACCESS_NSD
) {
1941 struct NSDeviceQueryResult nsdqr
;
1943 nsdqr
.SizeAvailable
= 0;
1944 nsdqr
.DevQueryFormat
= 0;
1945 io
->iotd_Req
.io_Command
= NSCMD_DEVICEQUERY
;
1946 io
->iotd_Req
.io_Length
= sizeof(nsdqr
);
1947 io
->iotd_Req
.io_Data
= (APTR
)&nsdqr
;
1948 if (DoIO((struct IORequest
*)io
) != 0)
1950 if (!((io
->iotd_Req
.io_Actual
>= 16) && (io
->iotd_Req
.io_Actual
<= sizeof(nsdqr
)) && (nsdqr
.SizeAvailable
== io
->iotd_Req
.io_Actual
)))
1952 if(nsdqr
.DeviceType
!= NSDEVTYPE_TRACKDISK
)
1954 for(cmdcheck
= nsdqr
.SupportedCommands
; *cmdcheck
; cmdcheck
++) {
1955 if(*cmdcheck
== NSCMD_TD_READ64
)
1963 if (g
->tdmode
== ACCESS_TD64
) {
1965 io
->iotd_Req
.io_Command
= TD_READ64
;
1966 io
->iotd_Req
.io_Length
= 0;
1967 io
->iotd_Req
.io_Data
= 0;
1968 io
->iotd_Req
.io_Offset
= 0;
1969 io
->iotd_Req
.io_Actual
= 0;
1970 err
= DoIO((struct IORequest
*)io
);
1971 if (err
!= 0 && err
!= IOERR_BADLENGTH
&& err
!= IOERR_BADADDRESS
)
1975 for (cnt
= 0; cnt
< 2; cnt
++) {
1976 fillbuffer(buffer
, cnt
, g
);
1977 io
->iotd_Req
.io_Command
= CMD_READ
;
1978 io
->iotd_Req
.io_Length
= BLOCKSIZE
;
1979 io
->iotd_Req
.io_Data
= buffer
;
1980 io
->iotd_Req
.io_Offset
= g
->lastblock
<< BLOCKSHIFT
;
1981 if (g
->tdmode
>= ACCESS_TD64
) {
1982 io
->iotd_Req
.io_Actual
= g
->lastblock
>> (32 - BLOCKSHIFT
);
1983 io
->iotd_Req
.io_Command
= g
->tdmode
== ACCESS_NSD
? NSCMD_TD_READ64
: TD_READ64
;
1985 if (DoIO((struct IORequest
*)io
) != 0)
1987 if (testbuffer(buffer
, cnt
, g
))
1993 static BOOL
testread_td(UBYTE
*buffer
, globaldata
*g
)
1998 DebugPutHex("testread_td mode=", g
->tdmode
);
2000 ok
= testread_td2(buffer
, g
);
2004 args
[0] = g
->tdmode
;
2006 g
->ErrorMsg
= _NormalErrorMsg
;
2007 (g
->ErrorMsg
)(ACCESS_DEBUG2
, args
, 1, g
);
2011 DebugPutHex("testread_td ret=", ok
);
2016 BOOL
detectaccessmode(UBYTE
*buffer
, globaldata
*g
)
2019 BOOL inside4G
= g
->lastblock
< (0x80000000ul
>> (BLOCKSHIFT
- 1));
2021 BCPLtoCString(name
, (UBYTE
*)BADDR(g
->startup
->fssm_Device
));
2025 args
[0] = (ULONG
)name
;
2026 args
[1] = g
->startup
->fssm_Unit
;
2027 args
[2] = g
->firstblock
;
2028 args
[3] = g
->lastblock
;
2029 args
[4] = BLOCKSHIFT
;
2030 args
[5] = BLOCKSIZE
;
2032 g
->ErrorMsg
= _NormalErrorMsg
;
2033 (g
->ErrorMsg
)(ACCESS_DEBUG1
, args
, 1, g
);
2035 DebugPutHex("firstblock", g
->firstblock
);
2036 DebugPutHex("lastblock", g
->lastblock
);
2037 DebugPutHex("inside4G", inside4G
);
2038 DebugPutHex("maxtransfer", g
->maxtransfer
);
2042 /* if dostype = PDSx, test Direct SCSI first and always use it if test succeeded */
2043 if ((g
->dosenvec
->de_DosType
& 0xffffff00) == 0x50445300) {
2044 g
->tdmode
= ACCESS_DS
;
2045 if (testread_ds(buffer
, g
))
2050 if (g
->lastblock
< 262144) {
2051 /* Don't bother with tests if small enough (<128M) */
2052 g
->tdmode
= ACCESS_STD
;
2058 /* inside first 4G? Try standard CMD_READ first. */
2059 g
->tdmode
= ACCESS_STD
;
2060 if (testread_td(buffer
, g
))
2063 g
->tdmode
= ACCESS_DS
;
2064 /* It failed, we may have 1G limit A590 pre-7.0 ROM or CDTV SCSI, try DS */
2065 if (testread_ds(buffer
, g
))
2068 g
->tdmode
= ACCESS_STD
;
2069 /* Both failed. Panic! */
2070 args
[0] = g
->lastblock
;
2071 args
[1] = (ULONG
)name
;
2072 args
[2] = g
->startup
->fssm_Unit
;
2073 g
->ErrorMsg
= _NormalErrorMsg
;
2074 (g
->ErrorMsg
)(AFS_ERROR_32BIT_ACCESS_ERROR
, args
, 1, g
);
2077 /* outside of first 4G, must use TD64, NSD or DS */
2079 g
->tdmode
= ACCESS_NSD
;
2080 if (testread_td(buffer
, g
))
2084 g
->tdmode
= ACCESS_TD64
;
2085 if (testread_td(buffer
, g
))
2089 g
->tdmode
= ACCESS_DS
;
2090 if (testread_ds(buffer
, g
))
2097 g
->ErrorMsg
= _NormalErrorMsg
;
2098 (g
->ErrorMsg
)(ACCESS_DEBUG2
, args
, 1, g
);
2101 g
->tdmode
= ACCESS_STD
;
2106 /*************************************************************************/
2108 /* turn drivemotor off */
2109 void MotorOff(globaldata
*g
)
2111 struct IOExtTD
*request
= g
->request
;
2115 request
->iotd_Req
.io_Command
= TD_MOTOR
;
2116 request
->iotd_Req
.io_Length
= 0;
2117 request
->iotd_Count
= g
->changecount
;
2119 DoIO((struct IORequest
*)request
);