2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
10 #include <exec/types.h>
11 #include <devices/input.h>
12 #include <devices/newstyle.h>
13 #include <devices/trackdisk.h>
14 #include <exec/errors.h>
16 #include <hardware/custom.h>
17 #include <hardware/intbits.h>
18 #include <intuition/intuition.h>
21 #include "afsblocks.h"
23 #include "extstrings.h"
25 #include "baseredef.h"
28 * The deadlock bug caused by calling LockDosList() when adding avolume node
29 * has now been fixed, but a deadlock still occurs when trying to mount an
30 * AFS disk image with fdsk.device if the image file is on an AFS volume.
31 * This is because of there only being one filesystem process that is shared
32 * between all AFS devices.
35 // pushes an IECLASS event in the input stream.
36 static void SendEvent(struct AFSBase
*afsbase
, LONG event
) {
37 struct IOStdReq
*InputRequest
;
38 struct MsgPort
*InputPort
;
39 struct InputEvent
*ie
;
40 if ((InputPort
= (struct MsgPort
*)CreateMsgPort())) {
42 if ((InputRequest
= (struct IOStdReq
*)CreateIORequest(InputPort
, sizeof(struct IOStdReq
)))) {
44 if (!OpenDevice("input.device", 0, (struct IORequest
*)InputRequest
, 0)) {
46 if ((ie
= AllocVec(sizeof(struct InputEvent
), MEMF_PUBLIC
|MEMF_CLEAR
))) {
48 InputRequest
->io_Command
= IND_WRITEEVENT
;
49 InputRequest
->io_Data
= ie
;
50 InputRequest
->io_Length
= sizeof(struct InputEvent
);
52 DoIO((struct IORequest
*)InputRequest
);
56 CloseDevice((struct IORequest
*)InputRequest
);
58 DeleteIORequest ((APTR
)InputRequest
);
60 DeleteMsgPort (InputPort
);
64 /************************** DOS ******************************************/
65 /*******************************************
67 Descr.: initializes a devicelist structure
68 Input : devicelist - devicelist structure to initialize
69 rootblock - cacheblock of the rootblock
70 Output: DOSTRUE for success; DOSFALSE otherwise
71 ********************************************/
74 struct AFSBase
*afsbase
,
75 struct Volume
*volume
,
76 struct BlockCache
*rootblock
83 name
=(char *)rootblock
->buffer
+(BLK_DISKNAME_START(volume
)*4);
84 volume
->devicelist
.dl_Next
= 0;
85 volume
->devicelist
.dl_Type
= DLT_VOLUME
;
86 volume
->devicelist
.dl_Lock
= 0;
87 volume
->devicelist
.dl_VolumeDate
.ds_Days
=
88 AROS_BE2LONG(rootblock
->buffer
[BLK_ROOT_DAYS(volume
)]);
89 volume
->devicelist
.dl_VolumeDate
.ds_Minute
=
90 AROS_BE2LONG(rootblock
->buffer
[BLK_ROOT_MINS(volume
)]);
91 volume
->devicelist
.dl_VolumeDate
.ds_Tick
=
92 AROS_BE2LONG(rootblock
->buffer
[BLK_ROOT_TICKS(volume
)]);
93 volume
->devicelist
.dl_LockList
= 0;
94 volume
->devicelist
.dl_DiskType
= volume
->dostype
;
95 if (volume
->devicelist
.dl_Name
!= BNULL
)
97 newname
= volume
->devicelist
.dl_Name
;
101 newname
= MKBADDR(AllocVec(32,MEMF_CLEAR
| MEMF_PUBLIC
));
102 if (newname
== BNULL
)
105 for (i
=0; i
<name
[0]; i
++)
106 AROS_BSTR_putchar(newname
, i
, name
[i
+1]);
107 AROS_BSTR_setstrlen(newname
, name
[0]);
108 volume
->devicelist
.dl_Name
= newname
;
112 /*******************************************
113 Name : attemptAddDosVolume
114 Descr.: adds a new volume to dos
115 Input : volume - volume to add
116 Output: DOSTRUE for success; DOSFALSE otherwise
117 ********************************************/
118 LONG
attemptAddDosVolume(struct AFSBase
*afsbase
, struct Volume
*volume
) {
119 struct DosList
*doslist
;
120 struct DosList
*dl
=NULL
;
125 if (volume
->volumenode
) {
126 D(bug("[afs 0x%08lX] VolumeNode is already present!\n", volume
));
129 bname
= volume
->devicelist
.dl_Name
;
130 for (i
=0; i
<AROS_BSTR_strlen(bname
); i
++)
131 string
[i
] = AROS_BSTR_getchar(bname
,i
);
132 string
[AROS_BSTR_strlen(bname
)] = 0;
133 D(bug("[afs 0x%08lX] Processing inserted volume %s\n", volume
, string
));
134 /* is the volume already in the list? */
135 doslist
= AttemptLockDosList(LDF_WRITE
| LDF_VOLUMES
);
138 dl
= FindDosEntry(doslist
,string
,LDF_VOLUMES
);
139 UnLockDosList(LDF_WRITE
| LDF_VOLUMES
);
144 /* if not create a new doslist */
147 D(bug("[afs 0x%08lX] Creating new VolumeNode\n", volume
));
148 doslist
= MakeDosEntry(string
,DLT_VOLUME
);
151 doslist
->dol_Task
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
152 doslist
->dol_misc
.dol_volume
.dol_VolumeDate
.ds_Days
=
153 volume
->devicelist
.dl_VolumeDate
.ds_Days
;
154 doslist
->dol_misc
.dol_volume
.dol_VolumeDate
.ds_Minute
=
155 volume
->devicelist
.dl_VolumeDate
.ds_Minute
;
156 doslist
->dol_misc
.dol_volume
.dol_VolumeDate
.ds_Tick
=
157 volume
->devicelist
.dl_VolumeDate
.ds_Tick
;
158 AddDosEntry(doslist
);
159 /* if we re-use "volume" clear locklist */
160 volume
->locklist
= NULL
;
163 volume
->volumenode
= dl
;
164 SendEvent(afsbase
, IECLASS_DISKINSERTED
);
168 /*******************************************
170 Descr.: removes a volume added by addDosVolume
171 or if there are some locks active
173 Input : volume - volume to remove
175 ********************************************/
176 void remDosVolume(struct AFSBase
*afsbase
, struct Volume
*volume
) {
179 dl
= volume
->volumenode
;
181 if (volume
->locklist
!= NULL
)
183 D(bug("[afs 0x%08lX] VolumeNode in use, keeping as offline\n", volume
));
184 dl
->dol_misc
.dol_volume
.dol_LockList
= MKBADDR(volume
->locklist
);
188 D(bug("[afs 0x%08lX] Removing VolumeNode\n", volume
));
189 remDosNode(afsbase
, dl
);
191 volume
->volumenode
= NULL
;
195 /*******************************************
197 Descr.: removes a DOS volume node
198 Input : dl - volume to remove
200 ********************************************/
201 void remDosNode(struct AFSBase
*afsbase
, struct DosList
*dl
)
205 SendEvent(afsbase
, IECLASS_DISKREMOVED
);
209 (struct AFSBase
*afsbase
, struct Volume
*volume
, struct BlockCache
*block
)
211 if (!initDeviceList(afsbase
, volume
, block
))
212 return ERROR_NO_FREE_STORE
;
213 if (!attemptAddDosVolume(afsbase
, volume
))
215 showError(afsbase
, ERR_DOSENTRY
);
216 remDosVolume(afsbase
, volume
);
217 return ERROR_UNKNOWN
;
222 void osMediumFree(struct AFSBase
*afsbase
, struct Volume
*volume
, LONG all
) {
223 remDosVolume(afsbase
, volume
);
225 FreeVec(BADDR(volume
->devicelist
.dl_Name
));
228 /************************** I/O ******************************************/
229 struct IOExtTD
*openDevice
231 struct AFSBase
*afsbase
,
238 struct IOExtTD
*ioreq
;
240 ioreq
= (struct IOExtTD
*)CreateIORequest(mp
, sizeof(struct IOExtTD
));
243 if (OpenDevice(device
, unit
, (struct IORequest
*)ioreq
, flags
) == 0)
248 showError(afsbase
, ERR_DEVICE
, device
);
249 DeleteIORequest((struct IORequest
*)ioreq
);
254 void closeDevice(struct AFSBase
*afsbase
, struct IOExtTD
*ioreq
) {
255 if (ioreq
->iotd_Req
.io_Device
!= NULL
)
256 CloseDevice((struct IORequest
*)&ioreq
->iotd_Req
);
257 DeleteIORequest((APTR
)ioreq
);
261 (struct AFSBase
*afsbase
, struct IOHandle
*ioh
, struct DriveGeometry
*dg
)
263 ioh
->ioreq
->iotd_Req
.io_Command
= TD_GETGEOMETRY
;
264 ioh
->ioreq
->iotd_Req
.io_Data
= dg
;
265 ioh
->ioreq
->iotd_Req
.io_Length
= sizeof(struct DriveGeometry
);
266 return DoIO((struct IORequest
*)&ioh
->ioreq
->iotd_Req
);
269 AROS_INTP(changeIntCode
);
271 LONG
addChangeInt(struct AFSBase
*afsbase
, struct IOHandle
*ioh
) {
273 ioh
->mc_int
.is_Code
= (VOID_FUNC
)changeIntCode
;
274 ioh
->mc_int
.is_Data
= ioh
;
275 ioh
->iochangeint
->iotd_Req
.io_Command
= TD_ADDCHANGEINT
;
276 ioh
->iochangeint
->iotd_Req
.io_Flags
= 0;
277 ioh
->iochangeint
->iotd_Req
.io_Length
= sizeof(struct Interrupt
);
278 ioh
->iochangeint
->iotd_Req
.io_Data
= &ioh
->mc_int
;
279 ioh
->iochangeint
->iotd_Req
.io_Error
= 0;
280 SendIO((struct IORequest
*)&ioh
->iochangeint
->iotd_Req
);
281 return ioh
->iochangeint
->iotd_Req
.io_Error
;
284 void remChangeInt(struct AFSBase
*afsbase
, struct IOHandle
*ioh
) {
287 (ioh
->iochangeint
!= NULL
) &&
288 (ioh
->iochangeint
->iotd_Req
.io_Error
== 0)
291 ioh
->iochangeint
->iotd_Req
.io_Command
= TD_REMCHANGEINT
;
292 DoIO((struct IORequest
*)&ioh
->iochangeint
->iotd_Req
);
296 void checkAddChangeInt(struct AFSBase
*afsbase
, struct IOHandle
*ioh
) {
297 struct DriveGeometry dg
;
299 if (!getGeometry(afsbase
, ioh
, &dg
))
301 if (dg
.dg_Flags
& DGF_REMOVABLE
)
303 ioh
->iochangeint
= openDevice
304 (afsbase
, ioh
->mp
, ioh
->blockdevice
, ioh
->unit
, ioh
->flags
);
305 if (ioh
->iochangeint
!= NULL
)
307 addChangeInt(afsbase
, ioh
);
310 ioh
->sectorsize
= dg
.dg_SectorSize
;
314 UBYTE
diskPresent(struct AFSBase
*afsbase
, struct IOHandle
*ioh
) {
316 ioh
->ioreq
->iotd_Req
.io_Command
= TD_CHANGESTATE
;
317 DoIO((struct IORequest
*)&ioh
->ioreq
->iotd_Req
);
318 return ioh
->ioreq
->iotd_Req
.io_Actual
== 0;
321 BOOL
diskWritable(struct AFSBase
*afsbase
, struct IOHandle
*ioh
)
323 ioh
->ioreq
->iotd_Req
.io_Command
= TD_PROTSTATUS
;
324 DoIO((struct IORequest
*)&ioh
->ioreq
->iotd_Req
);
325 return ioh
->ioreq
->iotd_Req
.io_Actual
== 0;
328 ULONG
sectorSize(struct AFSBase
*afsbase
, struct IOHandle
*ioh
)
330 return ioh
->sectorsize
;
333 struct IOHandle
*openBlockDevice(struct AFSBase
*afsbase
, struct IOHandle
*ioh
)
336 ioh
->mp
= CreateMsgPort();
339 ioh
->ioreq
= openDevice(afsbase
, ioh
->mp
, ioh
->blockdevice
, ioh
->unit
, ioh
->flags
);
340 if (ioh
->ioreq
!= NULL
)
342 ioh
->cmdread
= CMD_READ
;
343 ioh
->cmdwrite
= CMD_WRITE
;
344 ioh
->cmdseek
= TD_SEEK
;
345 ioh
->cmdformat
= TD_FORMAT
;
346 ioh
->afsbase
= afsbase
;
347 if (diskPresent(afsbase
, ioh
))
348 ioh
->ioflags
|= IOHF_DISK_IN
;
349 checkAddChangeInt(afsbase
, ioh
);
352 DeleteMsgPort(ioh
->mp
);
357 void closeBlockDevice(struct AFSBase
*afsbase
, struct IOHandle
*ioh
) {
359 remChangeInt(afsbase
, ioh
);
360 if (ioh
->iochangeint
!= NULL
)
361 closeDevice(afsbase
, ioh
->iochangeint
);
362 if (ioh
->ioreq
!= NULL
)
363 closeDevice(afsbase
, ioh
->ioreq
);
365 DeleteMsgPort(ioh
->mp
);
368 void motorOff(struct AFSBase
*afsbase
, struct IOHandle
*ioh
) {
370 ioh
->ioreq
->iotd_Req
.io_Command
= TD_MOTOR
;
371 ioh
->ioreq
->iotd_Req
.io_Length
= 0;
372 DoIO((struct IORequest
*)&ioh
->ioreq
->iotd_Req
);
375 void checkDeviceFlags(struct AFSBase
*afsbase
) {
376 struct Volume
*volume
;
377 struct IOHandle
*ioh
;
379 volume
= (struct Volume
*)afsbase
->device_list
.lh_Head
;
380 while (volume
->ln
.ln_Succ
!= NULL
)
383 if ((ioh
->ioflags
& IOHF_MEDIA_CHANGE
) && (!volume
->inhibitcounter
))
385 D(bug("[afs 0x%08lX] Media change signalled\n", volume
));
386 if (diskPresent(afsbase
, ioh
))
388 if (!volume
->inhibitcounter
)
390 D(bug("[afs 0x%08lX] Media inserted\n", volume
));
391 newMedium(afsbase
, volume
);
393 ioh
->ioflags
|= IOHF_DISK_IN
;
397 if (!volume
->inhibitcounter
)
399 flush(afsbase
, volume
);
400 remDosVolume(afsbase
, volume
);
402 ioh
->ioflags
&= ~IOHF_DISK_IN
;
404 ioh
->ioflags
&= ~IOHF_MEDIA_CHANGE
;
406 volume
= (struct Volume
*)volume
->ln
.ln_Succ
;
410 void check64BitSupport(struct AFSBase
*afsbase
, struct Volume
*volume
) {
411 struct NSDeviceQueryResult nsdq
;
416 (volume
->startblock
+(volume
->countblocks
))* /* last block */
417 (volume
->SizeBlock
*4/512) /* 1 portion (block) equals 512 (bytes) */
420 nsdq
.SizeAvailable
= 0;
421 nsdq
.DevQueryFormat
= 0;
422 volume
->ioh
.ioreq
->iotd_Req
.io_Command
= NSCMD_DEVICEQUERY
;
423 volume
->ioh
.ioreq
->iotd_Req
.io_Data
= &nsdq
;
424 volume
->ioh
.ioreq
->iotd_Req
.io_Length
= sizeof(struct NSDeviceQueryResult
);
425 if (DoIO((struct IORequest
*)volume
->ioh
.ioreq
) == IOERR_NOCMD
)
427 D(bug("[afs] initVolume-NSD: device doesn't understand NSD-Query\n"));
432 (volume
->ioh
.ioreq
->iotd_Req
.io_Actual
> sizeof(struct NSDeviceQueryResult
)) ||
433 (volume
->ioh
.ioreq
->iotd_Req
.io_Actual
== 0) ||
434 (volume
->ioh
.ioreq
->iotd_Req
.io_Actual
!= nsdq
.SizeAvailable
)
437 D(bug("[afs] initVolume-NSD: WARNING wrong io_Actual using NSD\n"));
441 D(bug("[afs] initVolume-NSD: using NSD commands\n"));
442 if (nsdq
.DeviceType
!= NSDEVTYPE_TRACKDISK
)
443 D(bug("[afs] initVolume-NSD: WARNING no trackdisk type\n"));
444 for (cmdcheck
=nsdq
.SupportedCommands
; *cmdcheck
; cmdcheck
++)
446 if (*cmdcheck
== NSCMD_TD_READ64
)
447 volume
->ioh
.cmdread
= NSCMD_TD_READ64
;
448 if (*cmdcheck
== NSCMD_TD_WRITE64
)
449 volume
->ioh
.cmdwrite
= NSCMD_TD_WRITE64
;
450 if (*cmdcheck
== NSCMD_TD_SEEK64
)
451 volume
->ioh
.cmdseek
= NSCMD_TD_SEEK64
;
452 if (*cmdcheck
== NSCMD_TD_FORMAT64
)
453 volume
->ioh
.cmdformat
= NSCMD_TD_FORMAT64
;
456 (volume
->ioh
.cmdread
!= NSCMD_TD_READ64
) ||
457 (volume
->ioh
.cmdwrite
!= NSCMD_TD_WRITE64
)
459 D(bug("[afs] initVolume-NSD: WARNING no READ64/WRITE64\n"));
465 D(bug("[afs] initVolume-NSD: no need for NSD\n"));
469 /*******************************************
471 Descr.: flush buffers and update disk (sync)
472 Input : volume - volume to flush
474 ********************************************/
475 BOOL
flush(struct AFSBase
*afsbase
, struct Volume
*volume
) {
477 flushCache(afsbase
, volume
);
478 volume
->ioh
.ioreq
->iotd_Req
.io_Command
= CMD_UPDATE
;
479 DoIO((struct IORequest
*)&volume
->ioh
.ioreq
->iotd_Req
);
480 clearCache(afsbase
, volume
->blockcache
);
484 static ULONG readwriteDisk
486 struct AFSBase
*afsbase
,
487 struct Volume
*volume
,
495 struct IOHandle
*ioh
= &volume
->ioh
;
498 if (start
+ count
<= volume
->countblocks
)
500 ioh
->ioreq
->iotd_Req
.io_Command
= cmd
;
501 ioh
->ioreq
->iotd_Req
.io_Length
= count
*BLOCK_SIZE(volume
);
502 ioh
->ioreq
->iotd_Req
.io_Data
= mem
;
504 offset
= (UQUAD
)volume
->startblock
* volume
->sectorsize
505 + (UQUAD
)start
* BLOCK_SIZE(volume
);
507 ioh
->ioreq
->iotd_Req
.io_Offset
= 0xFFFFFFFF & offset
;
508 ioh
->ioreq
->iotd_Req
.io_Actual
= offset
>>32;
509 retval
= DoIO((struct IORequest
*)&ioh
->ioreq
->iotd_Req
);
510 ioh
->flags
|= IOHF_MOTOR_OFF
;
514 showText(afsbase
, "Attempted to read/write block outside range!\n\n"
515 "range: %lu-%lu, start: %lu, count: %lu",
516 volume
->startblock
, volume
->lastblock
,
517 volume
->startblock
+ start
* volume
->blocksectors
,
518 count
* volume
->blocksectors
);
524 LONG
readDisk(struct AFSBase
*afsbase
, struct Volume
*volume
, ULONG start
, ULONG count
, APTR data
) {
530 DB2(bug("[afs] readDisk: reading blocks %lu to %lu\n", start
, start
+count
-1));
531 result
= readwriteDisk(afsbase
, volume
, start
, count
, data
, volume
->ioh
.cmdread
);
535 retry
= showRetriableError(afsbase
, "Read error %ld on block %lu", result
, start
) == 1;
541 LONG
writeDisk(struct AFSBase
*afsbase
, struct Volume
*volume
, ULONG start
, ULONG count
, APTR data
) {
547 DB2(bug("[afs] writeDisk: writing blocks %lu to %lu\n", start
, start
+count
-1));
548 result
= readwriteDisk(afsbase
, volume
, start
, count
, data
, volume
->ioh
.cmdwrite
);
552 retry
= showRetriableError(afsbase
, "Write error %ld on block %lu", result
, start
) == 1;
560 AROS_INTH1(changeIntCode
, struct IOHandle
*, ioh
)
564 ioh
->ioflags
|= IOHF_MEDIA_CHANGE
;
565 Signal(ioh
->afsbase
->port
.mp_SigTask
, 1<<ioh
->afsbase
->port
.mp_SigBit
);