3 * Revision 2.5 1999/09/10 22:14:49 Michiel
6 * Revision 2.4 1999/05/07 16:49:00 Michiel
9 * Revision 2.3 1999/05/04 17:59:09 Michiel
10 * check mode, logfile, search rootblock implemented
13 * Revision 2.2 1999/05/04 04:27:13 Michiel
14 * debugged upto buildrext
16 * Revision 2.1 1999/04/30 12:17:58 Michiel
17 * Accepts OK disks, bitmapfix and hardlink fix works
19 * Revision 1.2 1999/04/22 15:26:05 Michiel
22 * Revision 1.1 1999/04/19 22:16:53 Michiel
25 * Device Access functies, inclusief cache etc.
32 #include <exec/memory.h>
33 #include <exec/errors.h>
34 #include <devices/trackdisk.h>
35 #include <devices/scsidisk.h>
36 #include <dos/filehandler.h>
37 #include <proto/exec.h>
38 #include <clib/alib_protos.h>
43 #define BLOCKSHIFT (volume.blockshift)
45 /**************************************
47 **************************************/
49 static struct cacheline
*c_GetCacheLine(uint32 bloknr
);
51 /**************************************
53 **************************************/
57 /**************************************
60 * Cache module. Implemented as proxy on device. This module has a problem
61 * at the end of the disk: it does not take partial cachelines into
62 * account. This is no real problem since it is only used for the reserved
63 * area which is located at the start of the partition.
64 **************************************/
67 * cacheline size: 4-8-16
68 * cachelines: 8-16-32-64-128
69 * size = linesize * nolines * blocksize
71 error_t
InitCache(uint32 linesize
, uint32 nolines
)
75 /* allocate memory for the cache */
76 if (!(cache
.cachelines
= calloc(nolines
, sizeof(struct cacheline
))))
77 return e_out_of_memory
;
79 cache
.linesize
= linesize
;
80 cache
.nolines
= nolines
;
81 NewList((struct List
*)&cache
.LRUqueue
);
82 NewList((struct List
*)&cache
.LRUpool
);
83 for (i
=0; i
<nolines
; i
++)
85 cache
.cachelines
[i
].blocknr
= CL_UNUSED
; /* a bloknr that is never used */
86 cache
.cachelines
[i
].data
= AllocBufMem(linesize
*volume
.blocksize
);
87 if (cache
.cachelines
[i
].data
)
89 MinAddHead(&cache
.LRUpool
, &cache
.cachelines
[i
]);
95 /* get block (of size 'bytes') from cache. Cache is per >device<.
97 error_t
c_GetBlock(uint8
*data
, uint32 bloknr
, uint32 bytes
)
99 uint32 lineblnr
, offset
, total
;
100 struct cacheline
*cl
= NULL
;
101 error_t error
= e_none
;
104 for (total
=0; total
<bytes
; total
+=volume
.blocksize
, bloknr
++, data
+=volume
.blocksize
)
106 lineblnr
= (bloknr
/ cache
.linesize
) * cache
.linesize
;
107 offset
= (bloknr
% cache
.linesize
);
108 cl
= c_GetCacheLine(lineblnr
);
112 memcpy(data
, cl
->data
+ offset
*volume
.blocksize
, volume
.blocksize
);
117 /* write block (of size 'bytes') to cache
119 error_t
c_WriteBlock(uint8
*data
, uint32 bloknr
, uint32 bytes
)
121 uint32 lineblnr
, offset
, total
;
122 struct cacheline
*cl
= NULL
;
123 error_t error
= e_none
;
126 for (total
=0; total
<bytes
; total
+=volume
.blocksize
, bloknr
++, data
+=volume
.blocksize
)
128 lineblnr
= (bloknr
/ cache
.linesize
) * cache
.linesize
;
129 offset
= (bloknr
% cache
.linesize
);
130 cl
= c_GetCacheLine(lineblnr
);
134 memcpy(cl
->data
+ offset
*volume
.blocksize
, data
, volume
.blocksize
);
140 /* (private) locale function to search a cacheline
142 static struct cacheline
*c_GetCacheLine(uint32 bloknr
)
145 struct cacheline
*cl
= NULL
;
148 for (i
=0; i
<cache
.nolines
; i
++)
150 if (cache
.cachelines
[i
].blocknr
== bloknr
)
152 cl
= &cache
.cachelines
[i
];
159 if (IsMinListEmpty(&cache
.LRUpool
))
161 cl
= (struct cacheline
*)cache
.LRUqueue
.mlh_TailPred
;
163 error
= volume
.writerawblocks(cl
->data
, cache
.linesize
, cl
->blocknr
);
167 cl
= HeadOf(&cache
.LRUpool
);
170 error
= volume
.getrawblocks(cl
->data
, cache
.linesize
, bloknr
);
173 cl
->blocknr
= bloknr
;
178 MinAddHead(&cache
.LRUqueue
, cl
);
182 /* update alle dirty blocks in the cache
184 void UpdateCache(void)
186 struct cacheline
*cl
;
189 for (cl
= HeadOf(&cache
.LRUqueue
); cl
->next
; cl
=cl
->next
)
193 error
= volume
.writerawblocks(cl
->data
, cache
.linesize
, cl
->blocknr
);
195 adderror("write error");
206 if (cache
.cachelines
)
209 for (i
= 0; i
< cache
.nolines
; i
++)
210 FreeBufMem(cache
.cachelines
[i
].data
);
212 free(cache
.cachelines
);
213 cache
.cachelines
= NULL
;
218 /**************************************
220 **************************************/
224 * Open the diskdevice passed in 'startup' and generate the
225 * messageport and request structure, returned in 'port'
226 * and 'request' resp.
229 * out port, request, trackdisk
231 BOOL
OpenDiskDevice(struct FileSysStartupMsg
*startup
, struct MsgPort
**port
,
232 struct IOExtTD
**request
, BOOL
*trackdisk
)
236 *port
= CreateMsgPort();
239 *request
= (struct IOExtTD
*)CreateIORequest(*port
, sizeof(struct IOExtTD
));
242 BCPLtoCString(name
, (UBYTE
*)BADDR(startup
->fssm_Device
));
243 *trackdisk
= (strcmp(name
, "trackdisk.device") == 0) || (strcmp(name
, "diskspare.device") == 0);
244 if(OpenDevice(name
, startup
->fssm_Unit
, (struct IORequest
*)*request
,
245 startup
->fssm_Flags
) == 0)
253 * Get blocks from device. Blocknrs are disk (not partition!) based
255 error_t
dev_GetBlocks(uint8
*buffer
, int32 blocks
, uint32 blocknr
)
257 struct IOExtTD
*request
;
258 uint32 io_length
, io_transfer
, io_offset
, io_actual
= 0, io_startblock
= 0;
263 if(blocknr
== -1) // blocknr of uninitialised anode
266 io_length
= blocks
<< volume
.blockshift
;
267 io_offset
= blocknr
<< volume
.blockshift
;
269 if (volume
.td64mode
|| volume
.nsdmode
) {
270 // upper 32 bit of offset
271 io_actual
= blocknr
>> (32-volume
.blockshift
);
272 io_startblock
= blocknr
;
275 while (io_length
> 0)
277 io_transfer
= min(io_length
, volume
.dosenvec
->de_MaxTransfer
);
278 io_transfer
&= ~(volume
.blocksize
-1);
279 request
= volume
.request
;
280 request
->iotd_Req
.io_Command
= CMD_READ
;
281 request
->iotd_Req
.io_Length
= io_transfer
;
282 request
->iotd_Req
.io_Data
= io_buffer
; // bufmemtype ??
283 request
->iotd_Req
.io_Offset
= io_offset
;
284 if (volume
.td64mode
) {
285 request
->iotd_Req
.io_Actual
= io_actual
;
286 request
->iotd_Req
.io_Command
= TD_READ64
;
287 } else if (volume
.nsdmode
) {
288 request
->iotd_Req
.io_Actual
= io_actual
;
289 request
->iotd_Req
.io_Command
= NSCMD_TD_READ64
;
292 if (DoIO((struct IORequest
*)request
))
294 volume
.showmsg("READ ERROR\n");
299 io_buffer
+= io_transfer
;
300 io_length
-= io_transfer
;
301 if (volume
.td64mode
|| volume
.nsdmode
) {
302 io_startblock
+= (io_transfer
>> volume
.blockshift
);
303 io_offset
= io_startblock
<< volume
.blockshift
;
304 io_actual
= io_startblock
>> (32-volume
.blockshift
);
306 io_offset
+= io_transfer
;
314 error_t
dev_GetBlocksDS(uint8
*buffer
, int32 blocks
, uint32 blocknr
)
317 uint32 transfer
, maxtransfer
;
321 if(blocknr
== -1) // blocknr of uninitialised anode
324 /* chop in maxtransfer chunks */
325 maxtransfer
= volume
.dosenvec
->de_MaxTransfer
>> volume
.blockshift
;
328 transfer
= min(blocks
,maxtransfer
);
329 *((UWORD
*)&cmdbuf
[0]) = 0x2800;
330 *((ULONG
*)&cmdbuf
[2]) = blocknr
;
331 *((ULONG
*)&cmdbuf
[6]) = transfer
<<8;
332 if (!DoSCSICommand(buffer
,transfer
<<BLOCKSHIFT
,cmdbuf
,10,SCSIF_READ
))
334 volume
.showmsg("READ ERROR\n");
340 buffer
+= transfer
<<BLOCKSHIFT
;
348 error_t
dev_WriteBlocksDummy(uint8
*buffer
, int32 blocks
, uint32 blocknr
)
353 error_t
dev_WriteBlocksDS(uint8
*buffer
, int32 blocks
, uint32 blocknr
)
356 ULONG transfer
, maxtransfer
;
363 /* chop in maxtransfer chunks */
364 maxtransfer
= volume
.dosenvec
->de_MaxTransfer
>> volume
.blockshift
;
367 transfer
= min(blocks
,maxtransfer
);
368 *((UWORD
*)&cmdbuf
[0]) = 0x2a00;
369 *((ULONG
*)&cmdbuf
[2]) = blocknr
;
370 *((ULONG
*)&cmdbuf
[6]) = transfer
<<8;
371 if (!DoSCSICommand(buffer
,blocks
<<BLOCKSHIFT
,cmdbuf
,10,SCSIF_WRITE
))
373 volume
.showmsg("WRITE ERROR\n");
375 return e_write_error
;
379 buffer
+= transfer
<<BLOCKSHIFT
;
387 error_t
dev_WriteBlocks(uint8
*buffer
, int32 blocks
, uint32 blocknr
)
389 struct IOExtTD
*request
;
390 uint32 io_length
, io_transfer
, io_offset
, io_actual
= 0, io_startblock
= 0;
395 if(blocknr
== -1) // blocknr of uninitialised anode
396 return e_write_error
;
398 io_length
= blocks
<< volume
.blockshift
;
399 io_offset
= blocknr
<< volume
.blockshift
;
401 if (volume
.td64mode
|| volume
.nsdmode
) {
402 // upper 32 bit of offset
403 io_actual
= blocknr
>> (32 - BLOCKSHIFT
);
404 io_startblock
= blocknr
;
409 io_transfer
= min(io_length
, volume
.dosenvec
->de_MaxTransfer
);
410 io_transfer
&= ~(volume
.blocksize
-1);
411 request
= volume
.request
;
412 request
->iotd_Req
.io_Command
= CMD_WRITE
;
413 request
->iotd_Req
.io_Length
= io_transfer
;
414 request
->iotd_Req
.io_Data
= io_buffer
; // bufmemtype ??
415 request
->iotd_Req
.io_Offset
= io_offset
;
416 if (volume
.td64mode
) {
417 request
->iotd_Req
.io_Actual
= io_actual
;
418 request
->iotd_Req
.io_Command
= TD_WRITE64
;
419 } else if (volume
.nsdmode
) {
420 request
->iotd_Req
.io_Actual
= io_actual
;
421 request
->iotd_Req
.io_Command
= NSCMD_TD_WRITE64
;
424 if (DoIO((struct IORequest
*)request
))
426 volume
.showmsg("WRITE ERROR\n");
428 return e_write_error
;
431 io_buffer
+= io_transfer
;
432 io_length
-= io_transfer
;
433 if (volume
.td64mode
|| volume
.nsdmode
) {
434 io_startblock
+= (io_transfer
>> volume
.blockshift
);
435 io_offset
= io_startblock
<< volume
.blockshift
;
436 io_actual
= io_startblock
>> (32-volume
.blockshift
);
438 io_offset
+= io_transfer
;
446 * Allocation of memory for buffers
449 void *AllocBufMem(uint32 size
)
453 buffer
= AllocVec(size
, volume
.dosenvec
->de_BufMemType
|MEMF_CLEAR
);
455 if (((uint32
)buffer
) & ~volume
.dosenvec
->de_Mask
)
457 volume
.showmsg ("Memory mask fails - aborting\n");
465 void FreeBufMem (void *mem
)
471 * Do direct scsi command
474 static uint8 sense
[20];
475 static struct SCSICmd scsicmd
;
477 int DoSCSICommand(UBYTE
*data
, ULONG datalen
, UBYTE
*command
,
478 UWORD commandlen
, UBYTE direction
)
480 scsicmd
.scsi_Data
= (UWORD
*)data
;
481 scsicmd
.scsi_Length
= datalen
;
482 scsicmd
.scsi_Command
= command
;
483 scsicmd
.scsi_CmdLength
= commandlen
;
484 scsicmd
.scsi_Flags
= SCSIF_AUTOSENSE
| direction
; /* SCSIF_READ or SCSIF_WRITE */
485 scsicmd
.scsi_SenseData
= sense
;
486 scsicmd
.scsi_SenseLength
= 18;
487 scsicmd
.scsi_SenseActual
= 0;
489 volume
.request
->iotd_Req
.io_Length
= sizeof(struct SCSICmd
);
490 volume
.request
->iotd_Req
.io_Data
= (APTR
)&scsicmd
;
491 volume
.request
->iotd_Req
.io_Command
= HD_SCSICMD
;
492 DoIO((struct IORequest
*)volume
.request
);
493 if (scsicmd
.scsi_Status
)
499 /* Convert BCPL/Pascal string to a CString.
500 * dest: resulting c string
501 * src: source pascal string (no BPTR!)
503 UBYTE
*BCPLtoCString(STRPTR dest
, UBYTE
*src
)
508 len
= min (len
, PATHSIZE
);
512 *(dest
++) = *(src
++);
518 /* ACCESS MODE AUTODETECT */
520 #define BLOCKSHIFT (volume.blockshift)
521 #define BLOCKSIZE (volume.blocksize)
523 static void fillbuffer(UBYTE
*buffer
, UBYTE data
)
525 memset (buffer
, data
+ 1, BLOCKSIZE
);
527 /* Check if at least one byte has changed */
528 static BOOL
testbuffer(UBYTE
*buffer
, UBYTE data
)
532 for (cnt
= 0; cnt
< BLOCKSIZE
; cnt
++) {
533 if (buffer
[cnt
] != data
+ 1)
539 static BOOL
testread_ds(UBYTE
*buffer
)
544 for (cnt
= 0; cnt
< 2; cnt
++) {
547 fillbuffer(buffer
, 0xfe);
549 *((UWORD
*)&cmdbuf
[0]) = 0x2500;
550 *((ULONG
*)&cmdbuf
[2]) = 0;
551 *((ULONG
*)&cmdbuf
[6]) = 0;
552 if (!DoSCSICommand(buffer
, 8, cmdbuf
, 10, SCSIF_READ
)) {
555 capacity
= *((ULONG
*)buffer
);
557 if (volume
.lastblock
> capacity
) {
560 fillbuffer(buffer
, cnt
);
562 *((UWORD
*)&cmdbuf
[0]) = 0x2800;
563 *((ULONG
*)&cmdbuf
[2]) = volume
.lastblock
;
564 *((ULONG
*)&cmdbuf
[6]) = 1 << 8;
565 if (!DoSCSICommand(buffer
, 1 << BLOCKSHIFT
, cmdbuf
, 10, SCSIF_READ
)) {
568 if (testbuffer(buffer
, cnt
)) {
575 static BOOL
testread_td(UBYTE
*buffer
)
577 struct IOExtTD
*io
= volume
.request
;
580 if (volume
.accessmode
== ACCESS_NSD
) {
581 struct NSDeviceQueryResult nsdqr
;
583 nsdqr
.SizeAvailable
= 0;
584 nsdqr
.DevQueryFormat
= 0;
585 io
->iotd_Req
.io_Command
= NSCMD_DEVICEQUERY
;
586 io
->iotd_Req
.io_Length
= sizeof(nsdqr
);
587 io
->iotd_Req
.io_Data
= (APTR
)&nsdqr
;
588 if (DoIO((struct IORequest
*)io
) != 0)
590 if (!((io
->iotd_Req
.io_Actual
>= 16) && (io
->iotd_Req
.io_Actual
<= sizeof(nsdqr
)) && (nsdqr
.SizeAvailable
== io
->iotd_Req
.io_Actual
)))
592 if(nsdqr
.DeviceType
!= NSDEVTYPE_TRACKDISK
)
594 for(cmdcheck
= nsdqr
.SupportedCommands
; *cmdcheck
; cmdcheck
++) {
595 if(*cmdcheck
== NSCMD_TD_READ64
)
601 if (volume
.accessmode
== ACCESS_TD64
) {
603 io
->iotd_Req
.io_Command
= TD_READ64
;
604 io
->iotd_Req
.io_Length
= 0;
605 io
->iotd_Req
.io_Data
= 0;
606 io
->iotd_Req
.io_Offset
= 0;
607 io
->iotd_Req
.io_Actual
= 0;
608 err
= DoIO((struct IORequest
*)io
);
609 if (err
!= 0 && err
!= IOERR_BADLENGTH
&& err
!= IOERR_BADADDRESS
)
612 for (cnt
= 0; cnt
< 2; cnt
++) {
613 fillbuffer(buffer
, cnt
);
614 io
->iotd_Req
.io_Command
= CMD_READ
;
615 io
->iotd_Req
.io_Length
= BLOCKSIZE
;
616 io
->iotd_Req
.io_Data
= buffer
;
617 io
->iotd_Req
.io_Offset
= volume
.lastblock
<< BLOCKSHIFT
;
618 if (volume
.accessmode
>= ACCESS_TD64
) {
619 io
->iotd_Req
.io_Actual
= volume
.lastblock
>> (32 - BLOCKSHIFT
);
620 io
->iotd_Req
.io_Command
= volume
.accessmode
== ACCESS_NSD
? NSCMD_TD_READ64
: TD_READ64
;
622 if (DoIO((struct IORequest
*)io
) != 0)
624 if (testbuffer(buffer
, cnt
))
630 BOOL
DetectAccessmode(UBYTE
*buffer
, BOOL scsidirectfirst
)
632 BOOL inside4G
= volume
.lastblock
< (0x80000000ul
>> (BLOCKSHIFT
- 1));
634 if (scsidirectfirst
) {
635 volume
.accessmode
= ACCESS_DS
;
636 if (testread_ds(buffer
))
640 if (volume
.lastblock
< 262144) {
641 /* Don't bother with tests if small enough (<128M) */
642 volume
.accessmode
= ACCESS_STD
;
647 /* inside first 4G? Try standard CMD_READ first. */
648 volume
.accessmode
= ACCESS_STD
;
649 if (testread_td(buffer
))
651 volume
.accessmode
= ACCESS_DS
;
652 /* It failed, we may have 1G limit A590 pre-7.0 ROM or CDTV SCSI, try DS */
653 if (testread_ds(buffer
))
655 volume
.accessmode
= ACCESS_STD
;
658 /* outside of first 4G, must use TD64, NSD or DS */
659 volume
.accessmode
= ACCESS_NSD
;
660 if (testread_td(buffer
))
662 volume
.accessmode
= ACCESS_TD64
;
663 if (testread_td(buffer
))
665 volume
.accessmode
= ACCESS_DS
;
666 if (testread_ds(buffer
))
669 volume
.accessmode
= ACCESS_STD
;