6 #include <devices/scsidisk.h>
7 #include <devices/trackdisk.h>
8 #include <dos/filehandler.h>
9 #include <exec/errors.h>
10 #include <exec/interrupts.h>
12 #include <exec/memory.h>
13 #include <exec/types.h>
14 #include <proto/exec.h>
15 #include <devices/newstyle.h> /* Doesn't include exec/types.h which is why it is placed here */
18 #include <aros/asmcall.h>
22 #include "deviceio_protos.h"
25 #include "req_protos.h"
27 static inline ULONG
MULU64(ULONG m1
, ULONG m2
, ULONG
*res_lo
)
29 unsigned long long res
= (UQUAD
)m1
* (UQUAD
)m2
;
35 extern LONG
getbuffer(UBYTE
**tempbuffer
, ULONG
*maxblocks
);
36 extern void starttimeout(void);
38 /* The purpose of the deviceio code is to provide a layer which
39 supports block I/O to devices:
41 - Devices are accessed based on Logical Blocks (The partition
42 offset and SectorsPerBlock are taken into account).
44 - Devices can be acessed normally or using NSD, TD64 or SCSI
47 - MaxTransfer and Mask is handled automatically.
49 - Makes sure no accesses outside the partition are allowed. */
54 _TDEBUG(("UPDATE\n"));
55 globals
->ioreq
->io_Command
=CMD_UPDATE
;
56 globals
->ioreq
->io_Length
=0;
57 DoIO((struct IORequest
*)globals
->ioreq
);
62 _TDEBUG(("MOTOR OFF\n"));
63 globals
->ioreq
->io_Command
=TD_MOTOR
;
64 globals
->ioreq
->io_Length
=0;
65 DoIO((struct IORequest
*)globals
->ioreq
);
68 static UBYTE
*errordescription(LONG errorcode
)
70 if(errorcode
==TDERR_NotSpecified
|| errorcode
==TDERR_SeekError
) {
71 return("General device failure.\nThe disk is in an unreadable format.\n\n");
73 else if(errorcode
==TDERR_BadSecPreamble
|| errorcode
==TDERR_BadSecID
|| errorcode
==TDERR_BadSecHdr
|| errorcode
==TDERR_BadHdrSum
|| errorcode
==TDERR_BadSecSum
) {
74 return("Invalid or bad sector.\nThe disk is in an unreadable format.\n\n");
76 else if(errorcode
==TDERR_TooFewSecs
|| errorcode
==TDERR_NoSecHdr
) {
77 return("Not enough sectors found.\nThe disk is in an unreadable format.\n\n");
79 else if(errorcode
==TDERR_NoMem
) {
80 return("The device ran out of memory.\n\n");
82 else if(errorcode
==HFERR_SelfUnit
) {
85 else if(errorcode
==HFERR_DMA
) {
86 return("DMA error.\nThe transfering of data to/from the device failed.\n\n");
88 else if(errorcode
==HFERR_Parity
) {
89 return("Parity error.\nThe transfering of data to/from the device failed.\n\n");
91 else if(errorcode
==HFERR_SelTimeout
) {
92 return("Selection timeout.\nThe device doesn't respond.\n\n");
94 else if(errorcode
==HFERR_BadStatus
|| errorcode
==HFERR_Phase
) {
95 return("General device failure.\nThe device is in an invalid state.\n\n");
98 return("Unknown error.\n\n");
101 LONG
writeprotection(void)
103 globals
->ioreq2
->io_Command
=TD_PROTSTATUS
;
104 globals
->ioreq2
->io_Flags
=IOF_QUICK
;
106 if(DoIO((struct IORequest
*)globals
->ioreq2
)==0)
108 if(globals
->ioreq2
->io_Actual
==0) {
109 /* Not write protected */
110 return(ID_VALIDATED
);
113 /* Write protected */
114 return(ID_WRITE_PROTECTED
);
117 UBYTE
isdiskpresent(void)
121 globals
->ioreq2
->io_Command
=TD_CHANGESTATE
;
122 globals
->ioreq2
->io_Flags
=IOF_QUICK
;
124 if((errorcode
=DoIO((struct IORequest
*)globals
->ioreq2
))==0)
126 if(globals
->ioreq2
->io_Actual
==0) {
132 /* No disk inserted */
137 req("This device doesn't support disk change detection!\n"\
138 "(errorcode = %ld). SFS will now assume that a\n"\
139 "disk IS present.", "Ok", errorcode
);
141 /* If anything went wrong, we assume a disk is inserted. */
146 static AROS_INTH1(changeintserver
, struct IntData
*, intdata
)
150 *intdata
->diskchanged
=1;
151 Signal(intdata
->task
, intdata
->signal
);
157 static LONG __interrupt __saveds __asm
changeintserver(register __a1
struct IntData
*intdata
)
159 *intdata
->diskchanged
=1;
160 Signal(intdata
->task
, intdata
->signal
);
165 LONG
addchangeint(struct Task
*task
, ULONG signal
)
167 globals
->intdata
.diskchanged
=&globals
->diskchanged
;
168 globals
->intdata
.task
=task
;
169 globals
->intdata
.signal
=signal
;
171 globals
->changeint
.is_Data
=&globals
->intdata
;
172 globals
->changeint
.is_Code
=(VOID_FUNC
)changeintserver
;
174 globals
->ioreqchangeint
->io_Command
=TD_ADDCHANGEINT
;
175 globals
->ioreqchangeint
->io_Flags
=0;
176 globals
->ioreqchangeint
->io_Length
=sizeof(struct Interrupt
);
177 globals
->ioreqchangeint
->io_Data
=&globals
->changeint
;
178 globals
->ioreqchangeint
->io_Error
=0;
180 SendIO((struct IORequest
*)globals
->ioreqchangeint
);
182 return(globals
->ioreqchangeint
->io_Error
);
185 void removechangeint(void)
187 if(globals
->ioreqchangeint
!=0 && globals
->ioreqchangeint
->io_Error
==0)
189 globals
->ioreqchangeint
->io_Command
=TD_REMCHANGEINT
;
190 SendIO((struct IORequest
*)globals
->ioreqchangeint
);
194 ULONG
getchange(void)
199 d
=globals
->diskchanged
;
200 globals
->diskchanged
=0;
206 ULONG
deviceapiused(void)
208 if(globals
->scsidirect
==TRUE
) {
209 return(DAU_SCSIDIRECT
);
212 if(globals
->newstyledevice
==TRUE
) {
216 if(globals
->does64bit
==TRUE
) {
223 LONG
getgeometry(ULONG
*sectors
, ULONG
*sectorsize
)
225 struct DriveGeometry dg
;
228 if((!strcmp(globals
->ioreq
->io_Device
->dd_Library
.lib_Node
.ln_Name
, "scsi.device") && globals
->ioreq
->io_Device
->dd_Library
.lib_Version
<=39) ||
229 !strcmp(globals
->ioreq
->io_Device
->dd_Library
.lib_Node
.ln_Name
, "HardFrame.device") ||
230 !strcmp(globals
->ioreq
->io_Device
->dd_Library
.lib_Node
.ln_Name
, "scsidev.device") ||
231 !strcmp(globals
->ioreq
->io_Device
->dd_Library
.lib_Node
.ln_Name
, "hddisk.device") ||
232 !strcmp(globals
->ioreq
->io_Device
->dd_Library
.lib_Node
.ln_Name
, "statram.device") ||
233 !strcmp(globals
->ioreq
->io_Device
->dd_Library
.lib_Node
.ln_Name
, "ramdrive.device")) {
237 globals
->ioreq
->io_Command
=TD_GETGEOMETRY
;
238 globals
->ioreq
->io_Length
=sizeof(struct DriveGeometry
);
239 globals
->ioreq
->io_Flags
=0;
240 globals
->ioreq
->io_Actual
=0;
241 globals
->ioreq
->io_Data
=&dg
;
245 if((errorcode
=DoIO((struct IORequest
*)globals
->ioreq
))==0)
247 if(dg
.dg_SectorSize
==512 || dg
.dg_SectorSize
==1024 || dg
.dg_SectorSize
==2048 || dg
.dg_SectorSize
==4096 || dg
.dg_SectorSize
==8192 || dg
.dg_SectorSize
==16384 || dg
.dg_SectorSize
==32768) {
248 *sectors
=dg
.dg_TotalSectors
;
249 *sectorsize
=dg
.dg_SectorSize
;
252 errorcode
=IOERR_NOCMD
;
259 void changegeometry(struct DosEnvec
*de
)
261 ULONG sectorspercilinder
;
264 globals
->sectors_block
= de
->de_SectorPerBlock
;
265 globals
->bytes_sector
= de
->de_SizeBlock
<<2;
266 globals
->bytes_block
= globals
->bytes_sector
* de
->de_SectorPerBlock
;
268 _DEBUG(("%u sectors per block, %u bytes per sector, %u bytes per block\n", globals
->sectors_block
, globals
->bytes_sector
, globals
->bytes_block
));
270 bs
= globals
->bytes_block
;
272 globals
->shifts_block
= 0;
273 while ((bs
>>= 1) !=0 )
275 globals
->shifts_block
++;
278 globals
->mask_block
= globals
->bytes_block
-1;
280 _DEBUG(("Block shift: %u, mask: 0x%08X\n", globals
->shifts_block
, globals
->mask_block
));
282 /* Absolute offset on the entire disk are expressed in Sectors;
283 Offset relative to the start of the partition are expressed in Blocks */
285 sectorspercilinder
= de
->de_Surfaces
*de
->de_BlocksPerTrack
; // 32 bit
287 /* Get bounds of our device */
288 globals
->sector_low
= sectorspercilinder
* de
->de_LowCyl
;
289 globals
->sector_high
= sectorspercilinder
* (de
->de_HighCyl
+1);
291 _DEBUG(("%u sectors per cylinder, start sector %u, end sector %u\n", sectorspercilinder
, globals
->sector_low
, globals
->sector_high
));
294 * If our device starts from sector 0, we assume we are serving the whole device.
295 * In this case this can be a removable drive, and we may need to query the drive
296 * about its current geometry (this way we can support floppies where geometry may
299 if (globals
->sector_low
== 0)
301 ULONG totalsectors
=0,sectorsize
=0;
303 if(getgeometry(&totalsectors
, §orsize
)!=0) {
309 D(bug("[SFS] Given Sector size %lu, detected %lu\n", sectorsize
, globals
->bytes_sector
));
310 if(sectorsize
==globals
->bytes_sector
) {
311 globals
->sector_high
=totalsectors
;
314 req("Geometry could not be used because\n"\
315 "sectorsize does not match that of the\n"\
316 "mountlist (%ld<>%ld).\n"\
317 "Please notify the author.", "Continue", sectorsize
, globals
->bytes_sector
);
322 /* Set some more characteristics */
323 globals
->sectors_total
= globals
->sector_high
- globals
->sector_low
;
324 globals
->blocks_total
= globals
->sectors_total
/ globals
->sectors_block
;
325 globals
->byte_low
= (UQUAD
)globals
->sector_low
* globals
->bytes_sector
;
326 globals
->byte_high
= (UQUAD
)globals
->sector_high
* globals
->bytes_sector
;
328 _DEBUG(("Total: %u sectors, %u blocks\n", globals
->sectors_total
, globals
->blocks_total
));
329 _DEBUG(("Start offset 0x%llu, end offset 0x%llu\n", globals
->byte_low
, globals
->byte_high
));
333 static struct fsIORequest
*createiorequest(void)
335 struct fsIORequest
*fsi
;
337 if((fsi
=AllocMem(sizeof(struct fsIORequest
), MEMF_CLEAR
))!=0)
339 if((fsi
->ioreq
=(struct IOStdReq
*)CreateIORequest(globals
->msgport
, sizeof(struct IOStdReq
)))!=0)
341 fsi
->ioreq
->io_Device
=globals
->ioreq
->io_Device
;
342 fsi
->ioreq
->io_Unit
=globals
->ioreq
->io_Unit
;
346 FreeMem(fsi
, sizeof(struct fsIORequest
));
354 LONG
initdeviceio(UBYTE
*devicename
, IPTR unit
, ULONG flags
, struct DosEnvec
*de
)
356 LONG errorcode
=ERROR_NO_FREE_STORE
;
358 if((globals
->msgport
=CreateMsgPort())!=0) {
359 if((globals
->ioreq
=(struct IOStdReq
*)CreateIORequest(globals
->msgport
, sizeof(struct IOStdReq
)))!=0) {
360 if((globals
->ioreq2
=(struct IOStdReq
*)CreateIORequest(globals
->msgport
, sizeof(struct IOStdReq
)))!=0) {
361 if((globals
->ioreqchangeint
=(struct IOStdReq
*)CreateIORequest(globals
->msgport
, sizeof(struct IOStdReq
)))!=0) {
362 if((errorcode
=OpenDevice(devicename
, unit
, (struct IORequest
*)globals
->ioreq
, flags
))==0) {
363 globals
->deviceopened
=TRUE
;
365 globals
->fsioreq
.ioreq
=globals
->ioreq
;
367 globals
->ioreq2
->io_Device
=globals
->ioreq
->io_Device
;
368 globals
->ioreq2
->io_Unit
=globals
->ioreq
->io_Unit
;
370 globals
->ioreqchangeint
->io_Device
=globals
->ioreq
->io_Device
;
371 globals
->ioreqchangeint
->io_Unit
=globals
->ioreq
->io_Unit
;
375 if(de
->de_TableSize
>=12) {
376 globals
->bufmemtype
=de
->de_BufMemType
;
378 if(de
->de_TableSize
>=13) {
379 globals
->blocks_maxtransfer
=de
->de_MaxTransfer
>>globals
->shifts_block
;
381 if(globals
->blocks_maxtransfer
==0) {
382 globals
->blocks_maxtransfer
=1;
385 if(de
->de_TableSize
>=14) {
386 globals
->mask_mask
=de
->de_Mask
;
391 /* If the partition's high byte is beyond the 4 GB border we will
392 try and detect a 64-bit device. */
394 if (globals
->byte_high
>> 32 != 0)
396 /* Check for 64-bit support (NSD/TD64/SCSI direct) */
397 struct NSDeviceQueryResult nsdqr
;
400 nsdqr
.SizeAvailable
=0;
401 nsdqr
.DevQueryFormat
=0;
403 globals
->ioreq
->io_Command
=NSCMD_DEVICEQUERY
;
404 globals
->ioreq
->io_Length
=sizeof(nsdqr
);
405 globals
->ioreq
->io_Data
=(APTR
)&nsdqr
;
407 if(DoIO((struct IORequest
*)globals
->ioreq
)==0 && (globals
->ioreq
->io_Actual
>= 16) && (nsdqr
.SizeAvailable
== globals
->ioreq
->io_Actual
) && (nsdqr
.DeviceType
== NSDEVTYPE_TRACKDISK
)) {
408 /* This must be a new style trackdisk device */
410 // req("New style device", "Ok");
412 globals
->newstyledevice
=TRUE
;
414 // _DEBUG(("Device is a new style device\n"));
416 /* Is it safe to use 64 bits with this driver? We can reject
417 bad mounts pretty easily via this check. */
419 for(cmdcheck
=nsdqr
.SupportedCommands
; *cmdcheck
; cmdcheck
++) {
420 if(*cmdcheck
== NSCMD_TD_READ64
) {
421 /* This trackdisk style device supports the complete 64-bit
422 command set without returning IOERR_NOCMD! */
424 // _DEBUG(("Device supports 64-bit commands\n"));
426 globals
->does64bit
=TRUE
;
427 globals
->cmdread
=NSCMD_TD_READ64
;
428 globals
->cmdwrite
=NSCMD_TD_WRITE64
;
432 else { /* Check for TD64 supporting devices */
435 globals
->ioreq
->io_Command
=24; /* READ64 */
436 globals
->ioreq
->io_Length
=0;
437 globals
->ioreq
->io_Actual
=0;
438 globals
->ioreq
->io_Offset
=0;
439 globals
->ioreq
->io_Data
=0;
441 td64errorcode
=DoIO((struct IORequest
*)globals
->ioreq
);
442 if(td64errorcode
!=-1 && td64errorcode
!=IOERR_NOCMD
) {
443 // req("TD64 device", "Ok");
445 globals
->does64bit
=TRUE
;
447 globals
->cmdwrite
=25;
449 else { /* Check for SCSI direct supporting devices */
452 if((destbuffer
=AllocVec(globals
->bytes_sector
,globals
->bufmemtype
))!=0) {
453 globals
->ioreq
->io_Command
=HD_SCSICMD
;
454 globals
->ioreq
->io_Length
=sizeof(struct SCSICmd
);
455 globals
->ioreq
->io_Data
=&globals
->scsicmd
;
457 globals
->scsicmd
.scsi_Data
=(UWORD
*)destbuffer
;
458 globals
->scsicmd
.scsi_Length
=globals
->bytes_sector
;
459 globals
->scsicmd
.scsi_Command
=(UBYTE
*)&globals
->scsi10cmd
;
460 globals
->scsicmd
.scsi_CmdLength
=sizeof(struct SCSI10Cmd
);
462 globals
->scsicmd
.scsi_Flags
=SCSIF_READ
;
464 globals
->scsicmd
.scsi_SenseData
=NULL
;
465 globals
->scsicmd
.scsi_SenseLength
=0;
466 globals
->scsicmd
.scsi_SenseActual
=0;
468 globals
->scsi10cmd
.Opcode
=SCSICMD_READ10
;
469 globals
->scsi10cmd
.Lun
=0;
470 globals
->scsi10cmd
.LBA
=globals
->sector_low
;
471 globals
->scsi10cmd
.Reserved
=0;
472 globals
->scsi10cmd
.Control
=0;
475 UWORD
*ptr
=(UWORD
*)&globals
->scsi10cmd
.Length
[0];
476 // scsi10cmd.Length=blocks*sectors_block; /* Odd aligned... */
480 if((td64errorcode
=DoIO((struct IORequest
*)globals
->ioreq
))==0) {
481 // req("SCSI direct command returned no error.", "Ok");
483 globals
->does64bit
=TRUE
;
484 globals
->scsidirect
=TRUE
;
485 globals
->cmdread
=SCSICMD_READ10
;
486 globals
->cmdwrite
=SCSICMD_WRITE10
;
492 // req("Not enough memory.", "Ok");
493 errorcode
=ERROR_NO_FREE_STORE
;
498 if(globals
->does64bit
==FALSE
) {
499 errorcode
=ERROR_NO_64BIT_SUPPORT
;
500 /* req("There is no 64-bit support, but your\n"\
501 "partition was (partially) located above 4 GB.", "Ok");
518 void cleanupdeviceio()
520 if(globals
->deviceopened
) {
521 CloseDevice((struct IORequest
*)globals
->ioreq
);
524 if(globals
->ioreq
!=0) {
525 DeleteIORequest((struct IORequest
*)globals
->ioreq
);
528 if(globals
->ioreq2
!=0) {
529 DeleteIORequest((struct IORequest
*)globals
->ioreq2
);
532 if(globals
->ioreqchangeint
!=0) {
533 DeleteIORequest((struct IORequest
*)globals
->ioreqchangeint
);
536 if(globals
->msgport
!=0) {
537 DeleteMsgPort(globals
->msgport
);
541 LONG
handleioerror(LONG errorcode
, UWORD action
, struct IOStdReq
*ioreq
)
543 if(errorcode
==TDERR_DiskChanged
) {
544 if(req("You MUST reinsert this volume!\n"\
545 "There still was some data which needs to be transferred.", "Retry|Cancel")<=0) {
549 else if(errorcode
==TDERR_WriteProt
|| (action
==DIO_WRITE
&& writeprotection()==ID_WRITE_PROTECTED
)) {
550 if(req("This volume is write protected.", "Retry|Cancel")<=0) {
551 return(ERROR_DISK_WRITE_PROTECTED
);
555 if(globals
->retries
-->0) {
560 if(req("There was an error while accessing this volume:\n\n%s"\
562 "io_Command = %ld\n"\
565 "io_Actual = %ld\n", "Retry|Cancel",
566 errordescription(errorcode
), errorcode
,
567 (ULONG
)ioreq
->io_Command
, ioreq
->io_Offset
,
568 ioreq
->io_Length
, ioreq
->io_Actual
)<=0) {
576 void setiorequest(struct fsIORequest
*fsi
, UWORD action
, UBYTE
*buffer
, ULONG blockoffset
, ULONG blocks
)
578 struct IOStdReq
*ioreq
=fsi
->ioreq
;
580 _DEBUG(("setiorequest(0x%p, %u, %u)\n", buffer
, blockoffset
, blocks
));
585 _DEBUG(("Use DirectSCSI: %d\n", globals
->scsidirect
));
587 if (globals
->scsidirect
==TRUE
)
589 ioreq
->io_Command
=HD_SCSICMD
;
590 ioreq
->io_Length
=sizeof(struct SCSICmd
);
591 ioreq
->io_Data
=&fsi
->scsicmd
;
593 fsi
->scsicmd
.scsi_Data
= (UWORD
*)buffer
;
594 fsi
->scsicmd
.scsi_Length
= blocks
<<globals
->shifts_block
;
595 fsi
->scsicmd
.scsi_Command
= (UBYTE
*)&fsi
->scsi10cmd
;
596 fsi
->scsicmd
.scsi_CmdLength
= sizeof(struct SCSI10Cmd
);
597 fsi
->scsicmd
.scsi_Flags
= (action
== DIO_READ
) ? SCSIF_READ
: 0;
598 fsi
->scsicmd
.scsi_SenseData
= NULL
;
599 fsi
->scsicmd
.scsi_SenseLength
= 0;
600 fsi
->scsicmd
.scsi_SenseActual
= 0;
602 fsi
->scsi10cmd
.Opcode
= action
==DIO_WRITE
? globals
->cmdwrite
: globals
->cmdread
; // SCSICMD_READ10 or SCSICMD_WRITE10;
603 fsi
->scsi10cmd
.Lun
= 0;
604 fsi
->scsi10cmd
.LBA
= globals
->sector_low
+blockoffset
*globals
->sectors_block
;
605 fsi
->scsi10cmd
.Reserved
= 0;
606 fsi
->scsi10cmd
.Control
= 0;
609 UWORD
*ptr
=(UWORD
*)&fsi
->scsi10cmd
.Length
[0];
611 // scsi10cmd.Length=blocks*sectors_block; /* Odd aligned... */
612 *ptr
=blocks
*globals
->sectors_block
;
617 ULONG startblock
= globals
->sector_low
/ globals
->sectors_block
;
618 UQUAD startoffset
= (UQUAD
)(startblock
+ blockoffset
) << globals
->shifts_block
;
620 ioreq
->io_Data
= buffer
;
621 ioreq
->io_Command
= action
==DIO_WRITE
? globals
->cmdwrite
: globals
->cmdread
;
622 ioreq
->io_Length
= blocks
<<globals
->shifts_block
;
623 ioreq
->io_Offset
= startoffset
;
624 ioreq
->io_Actual
= startoffset
>> 32;
628 LONG
transfer_buffered(UWORD action
, UBYTE
*buffer
, ULONG blockoffset
, ULONG blocklength
)
631 ULONG maxblocks
=globals
->blocks_maxtransfer
;
634 /* This function does a buffered transfer (in cases when the Mask
635 enforces it). It does not check if the parameters are within
636 the partition. Check those and the Mask before calling this
639 if ((errorcode
= getbuffer(&tempbuffer
, &maxblocks
)) != 0)
641 _DEBUG(("Buffered transfer: getbuffer() error %d\n", errorcode
));
646 while(blocklength
!=0)
648 ULONG blocks
=blocklength
>maxblocks
? maxblocks
: blocklength
;
650 setiorequest(&globals
->fsioreq
, action
, tempbuffer
, blockoffset
, blocks
);
652 if (action
==DIO_WRITE
)
653 CopyMemQuick(buffer
, tempbuffer
, blocks
<<globals
->shifts_block
);
655 /* We're about to do a physical disk access. (Re)set timeout. Since
656 the drive's motor will be turned off with the timeout as well we
657 always (re)set the timeout even if doio() would return an error. */
660 globals
->retries
=MAX_RETRIES
;
662 while ((errorcode
=DoIO((struct IORequest
*)globals
->fsioreq
.ioreq
)) != 0)
664 _DEBUG(("Buffered transfer: I/O error %d\n", errorcode
));
666 if ((errorcode
= handleioerror(errorcode
, action
, globals
->fsioreq
.ioreq
)) != 0)
668 _DEBUG(("Buffered transfer: SFS error %d\n", errorcode
));
673 if (action
==DIO_READ
)
674 CopyMemQuick(tempbuffer
, buffer
, blocks
<<globals
->shifts_block
);
678 buffer
+=blocks
<<globals
->shifts_block
;
684 LONG
waittransfers(void)
686 LONG firsterrorcode
=0;
689 /* This function waits for all the transfers in the iolist to
690 be completed. If any of them fails, the error is returned
691 (and perhaps a requester is put up). In any case, all of
692 the requests will be processed, errors or not, so you won't
693 have to call this function again in case of errors. */
695 while(globals
->iolist
!=0) {
696 struct fsIORequest
*next
=globals
->iolist
->next
;
698 if((errorcode
=WaitIO((struct IORequest
*)globals
->iolist
->ioreq
))!=0 && firsterrorcode
==0) {
699 while((errorcode
=handleioerror(errorcode
, globals
->iolist
->action
,
700 globals
->iolist
->ioreq
))==0) {
701 if((errorcode
=DoIO((struct IORequest
*)globals
->iolist
->ioreq
))==0) {
706 firsterrorcode
=errorcode
;
709 FreeMem(globals
->iolist
, sizeof(struct fsIORequest
));
710 globals
->iolist
=next
;
713 return(firsterrorcode
);
717 static LONG
asynctransfer(UWORD action
, UBYTE
*buffer
, ULONG blockoffset
, ULONG blocklength
)
719 /* Does asynchronous transfers, and returns before the transfer is completed.
720 Use waittransfers() to wait for all transfers done with this function to
721 complete. If this function returns an error, then you still must call
722 waittransfers(). Failure to do so will give unexpected results. */
724 if(blockoffset
< globals
->blocks_total
&& blockoffset
+blocklength
<= globals
->blocks_total
) {
725 ULONG maxblocks
=globals
->blocks_maxtransfer
;
727 if(((ULONG
)buffer
& ~globals
->mask_mask
)!=0) { // Buffered transfer needed?
728 return(transfer_buffered(action
, buffer
, blockoffset
, blocklength
));
731 while(blocklength
!=0) {
732 struct fsIORequest
*fsi
;
734 if((fsi
=createiorequest())!=0) {
735 ULONG blocks
=blocklength
>maxblocks
? maxblocks
: blocklength
;
737 setiorequest(fsi
, action
, buffer
, blockoffset
, blocks
);
739 /* We're about to do a physical disk access. (Re)set timeout. */
743 SendIO((struct IORequest
*)fsi
->ioreq
);
744 fsi
->next
=globals
->iolist
;
749 buffer
+=blocks
<<globals
->shifts_block
;
752 /* Some requests could already be in progress, so you must call
753 waittransfers() even if an error is returned. */
754 return(ERROR_NO_FREE_STORE
);
761 req("This volume tried to access a block\noutside its partition.\n(blockoffset = %ld, blocklength = %ld)\n", "Ok", blockoffset
, blocklength
);
763 return(ERROR_OUTSIDE_PARTITION
);
768 LONG
transfer(UWORD action
, UBYTE
*buffer
, ULONG blockoffset
, ULONG blocklength
)
770 _TDEBUG(("TRANSFER: %ld, buf=0x%p, block=%ld, blocks=%ld...\n", action
, buffer
, blockoffset
, blocklength
));
772 if ((blockoffset
< globals
->blocks_total
) && (blockoffset
+ blocklength
<= globals
->blocks_total
))
774 ULONG maxblocks
= globals
->blocks_maxtransfer
;
777 _DEBUG(("MaxTransfer: %d\n", maxblocks
));
779 // Buffered transfer needed?
780 if (((IPTR
)buffer
& ~globals
->mask_mask
) !=0 )
782 _DEBUG(("Buffer 0x%p, mask 0x%p. Buffered transfer needed.\n", buffer
, globals
->mask_mask
));
784 return transfer_buffered(action
, buffer
, blockoffset
, blocklength
);
787 while (blocklength
!=0)
789 ULONG blocks
= (blocklength
> maxblocks
) ? maxblocks
: blocklength
;
791 setiorequest(&globals
->fsioreq
, action
, buffer
, blockoffset
, blocks
);
793 /* We're about to do a physical disk access. (Re)set timeout. Since
794 the drive's motor will be turned off with the timeout as well we
795 always (re)set the timeout even if doio() would return an error. */
798 globals
->retries
=MAX_RETRIES
;
800 while ((errorcode
=DoIO((struct IORequest
*)globals
->fsioreq
.ioreq
)) != 0)
802 _DEBUG(("Direct transfer: I/O error %d\n", errorcode
));
804 if ((errorcode
=handleioerror(errorcode
, action
, globals
->fsioreq
.ioreq
)) != 0)
806 _DEBUG(("Direct transfer: SFS error %d\n", errorcode
));
814 buffer
+=blocks
<<globals
->shifts_block
;
824 req("This volume tried to access a block\noutside its partition.\n(blockoffset = %ld, blocklength = %ld)\n", "Ok", blockoffset
, blocklength
);
825 return(ERROR_OUTSIDE_PARTITION
);