includes: AROS_UFIxx -> AROS_INTxx change
[AROS.git] / rom / filesys / SFS / FS / deviceio.c
blobf1c10ea579edab4d5a1ba6cfa9ca8a75bce103e0
1 /*
2 #define DEBUG 1
3 #define DEBUGCODE
4 */
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>
11 #include <exec/io.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 */
17 #ifdef __AROS__
18 #include <aros/asmcall.h>
19 #endif
21 #include "deviceio.h"
22 #include "deviceio_protos.h"
23 #include "debug.h"
24 #include "globals.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;
31 *res_lo = res;
32 return res >> 32;
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
45 direct transparently.
47 - MaxTransfer and Mask is handled automatically.
49 - Makes sure no accesses outside the partition are allowed. */
52 void update(void)
54 _TDEBUG(("UPDATE\n"));
55 globals->ioreq->io_Command=CMD_UPDATE;
56 globals->ioreq->io_Length=0;
57 DoIO((struct IORequest *)globals->ioreq);
60 void motoroff(void)
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) {
83 return("\n\n");
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)
119 LONG errorcode;
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) {
127 /* Disk present */
128 return(TRUE);
130 else
132 /* No disk inserted */
133 return(FALSE);
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. */
142 return(TRUE);
145 #ifdef __AROS__
146 static AROS_INTH1(changeintserver, struct IntData *, intdata)
148 AROS_INTFUNC_INIT
150 *intdata->diskchanged=1;
151 Signal(intdata->task, intdata->signal);
152 return(0);
154 AROS_INTFUNC_EXIT
156 #else
157 static LONG __interrupt __saveds __asm changeintserver(register __a1 struct IntData *intdata)
159 *intdata->diskchanged=1;
160 Signal(intdata->task, intdata->signal);
161 return(0);
163 #endif
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)
196 ULONG d;
198 Disable();
199 d=globals->diskchanged;
200 globals->diskchanged=0;
201 Enable();
203 return(d);
206 ULONG deviceapiused(void)
208 if(globals->scsidirect==TRUE) {
209 return(DAU_SCSIDIRECT);
212 if(globals->newstyledevice==TRUE) {
213 return(DAU_NSD);
216 if(globals->does64bit==TRUE) {
217 return(DAU_TD64);
220 return(DAU_NORMAL);
223 LONG getgeometry(ULONG *sectors, ULONG *sectorsize)
225 struct DriveGeometry dg;
226 LONG errorcode;
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")) {
234 return(IOERR_NOCMD);
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;
243 dg.dg_SectorSize=0;
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;
251 else {
252 errorcode=IOERR_NOCMD;
256 return(errorcode);
259 void changegeometry(struct DosEnvec *de)
261 ULONG sectorspercilinder;
262 UWORD bs;
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
297 * vary (DD or HD)
299 if (globals->sector_low == 0)
301 ULONG totalsectors=0,sectorsize=0;
303 if(getgeometry(&totalsectors, &sectorsize)!=0) {
304 totalsectors=0;
307 if(totalsectors!=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;
313 else {
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));
332 #ifdef DEBUGCODE
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;
344 else
346 FreeMem(fsi, sizeof(struct fsIORequest));
350 return(fsi);
352 #endif
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;
373 changegeometry(de);
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;
398 UWORD *cmdcheck;
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 */
433 LONG td64errorcode;
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;
446 globals->cmdread=24;
447 globals->cmdwrite=25;
449 else { /* Check for SCSI direct supporting devices */
450 UWORD *destbuffer;
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... */
477 *ptr=1;
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;
489 FreeVec(destbuffer);
491 else {
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");
511 if(errorcode!=0) {
512 cleanupdeviceio();
515 return(errorcode);
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) {
546 return(errorcode);
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);
554 else {
555 if(globals->retries-->0) {
556 // Delay(2);
557 return(0);
560 if(req("There was an error while accessing this volume:\n\n%s"\
561 "errorcode = %ld\n"\
562 "io_Command = %ld\n"\
563 "io_Offset = %ld\n"\
564 "io_Length = %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) {
569 return(errorcode);
573 return(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));
582 fsi->next=0;
583 fsi->action=action;
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;
615 else
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)
630 UBYTE *tempbuffer;
631 ULONG maxblocks=globals->blocks_maxtransfer;
632 LONG errorcode;
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
637 function. */
639 if ((errorcode = getbuffer(&tempbuffer, &maxblocks)) != 0)
641 _DEBUG(("Buffered transfer: getbuffer() error %d\n", errorcode));
643 return 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. */
659 starttimeout();
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));
669 return(errorcode);
673 if (action==DIO_READ)
674 CopyMemQuick(tempbuffer, buffer, blocks<<globals->shifts_block);
676 blocklength-=blocks;
677 blockoffset+=blocks;
678 buffer+=blocks<<globals->shifts_block;
681 return(0);
684 LONG waittransfers(void)
686 LONG firsterrorcode=0;
687 LONG errorcode;
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) {
702 break;
706 firsterrorcode=errorcode;
709 FreeMem(globals->iolist, sizeof(struct fsIORequest));
710 globals->iolist=next;
713 return(firsterrorcode);
716 #if 0
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. */
741 starttimeout();
743 SendIO((struct IORequest *)fsi->ioreq);
744 fsi->next=globals->iolist;
745 globals->iolist=fsi;
747 blocklength-=blocks;
748 blockoffset+=blocks;
749 buffer+=blocks<<globals->shifts_block;
751 else {
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);
758 return(0);
760 else {
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);
766 #endif
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;
775 LONG errorcode;
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. */
797 starttimeout();
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));
808 return errorcode;
812 blocklength-=blocks;
813 blockoffset+=blocks;
814 buffer+=blocks<<globals->shifts_block;
817 _DEBUG(("..."));
818 _TDEBUG(("\n"));
820 return(0);
822 else
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);