2 Copyright © 2004-2014, The AROS Development Team. All rights reserved
9 #include <aros/debug.h>
10 #include <exec/exec.h>
11 #include <exec/resident.h>
12 #include <hidd/hidd.h>
13 #include <utility/utility.h>
14 #include <utility/tagitem.h>
18 #include <proto/exec.h>
19 #include <proto/oop.h>
23 #include LC_LIBDEFS_FILE
27 //---------------------------IO Commands---------------------------------------
29 /* Invalid comand does nothing, complains only. */
30 static void cmd_Invalid(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
32 D(bug("[ATA%02ld] cmd_Invalid: %d\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, io
->io_Command
));
33 io
->io_Error
= IOERR_NOCMD
;
36 /* Don't need to reset the drive? */
37 static void cmd_Reset(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
39 IOStdReq(io
)->io_Actual
= 0;
42 /* CMD_READ implementation */
43 static void cmd_Read32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
45 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
47 if (AF_Removable
== (unit
->au_Flags
& (AF_Removable
| AF_DiscPresent
)))
49 D(bug("[ATA%02ld] cmd_Read32: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit
->au_UnitNum
));
50 io
->io_Error
= TDERR_DiskChanged
;
54 ULONG block
= IOStdReq(io
)->io_Offset
;
55 ULONG count
= IOStdReq(io
)->io_Length
;
57 D(bug("[ATA%02ld] cmd_Read32(%08x, %08x)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, block
, count
));
59 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
62 During this IO call it should be sure that both offset and
63 length are already aligned properly to sector boundaries.
65 if ((block
& mask
) | (count
& mask
))
67 D(bug("[ATA%02ld] cmd_Read32: offset or length not sector-aligned.\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
68 cmd_Invalid(io
, LIBBASE
);
72 block
>>= unit
->au_SectorShift
;
73 count
>>= unit
->au_SectorShift
;
76 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity
))
78 bug("[ATA%02ld] cmd_Read32: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, block
, count
, unit
->au_Capacity
);
79 io
->io_Error
= IOERR_BADADDRESS
;
83 /* Call the Unit's access funtion */
84 io
->io_Error
= unit
->au_Read32(unit
, block
, count
,
85 IOStdReq(io
)->io_Data
, &cnt
);
87 IOStdReq(io
)->io_Actual
= cnt
;
92 NSCMD_TD_READ64, TD_READ64 implementation. Basically the same, just packs
93 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
95 static void cmd_Read64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
97 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
99 if (AF_Removable
== (unit
->au_Flags
& (AF_Removable
| AF_DiscPresent
)))
101 D(bug("[ATA%02ld] cmd_Read64: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit
->au_UnitNum
));
102 io
->io_Error
= TDERR_DiskChanged
;
106 UQUAD block
= IOStdReq(io
)->io_Offset
| (UQUAD
)(IOStdReq(io
)->io_Actual
) << 32;
107 ULONG count
= IOStdReq(io
)->io_Length
;
109 D(bug("[ATA%02ld] cmd_Read64(%08x-%08x, %08x)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, IOStdReq(io
)->io_Actual
, IOStdReq(io
)->io_Offset
, count
));
111 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
113 if ((block
& (UQUAD
)mask
) | (count
& mask
) | (count
== 0))
115 D(bug("[ATA%02ld] cmd_Read64: offset or length not sector-aligned.\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
116 cmd_Invalid(io
, LIBBASE
);
120 block
>>= unit
->au_SectorShift
;
121 count
>>= unit
->au_SectorShift
;
125 If the sum of sector offset and the sector count doesn't overflow
126 the 28-bit LBA address, use 32-bit access for speed and simplicity.
127 Otherwise do the 48-bit LBA addressing.
129 if ((block
+ count
) < 0x0fffffff)
131 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity
))
133 bug("[ATA%02ld] cmd_Read64: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, block
, count
, unit
->au_Capacity
);
134 io
->io_Error
= IOERR_BADADDRESS
;
137 io
->io_Error
= unit
->au_Read32(unit
, (ULONG
)(block
& 0x0fffffff), count
, IOStdReq(io
)->io_Data
, &cnt
);
141 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity48
))
143 bug("[ATA%02ld] cmd_Read64: Requested block (%lx:%08lx;%ld) outside disk range (%lx:%08lx)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, block
>>32, block
&0xfffffffful
, count
, unit
->au_Capacity48
>>32, unit
->au_Capacity48
& 0xfffffffful
);
144 io
->io_Error
= IOERR_BADADDRESS
;
148 io
->io_Error
= unit
->au_Read64(unit
, block
, count
, IOStdReq(io
)->io_Data
, &cnt
);
151 IOStdReq(io
)->io_Actual
= cnt
;
155 /* CMD_WRITE implementation */
156 static void cmd_Write32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
158 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
160 if (AF_Removable
== (unit
->au_Flags
& (AF_Removable
| AF_DiscPresent
)))
162 D(bug("[ATA%02ld] cmd_Write32: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit
->au_UnitNum
));
163 io
->io_Error
= TDERR_DiskChanged
;
167 ULONG block
= IOStdReq(io
)->io_Offset
;
168 ULONG count
= IOStdReq(io
)->io_Length
;
170 D(bug("[ATA%02ld] cmd_Write32(%08x, %08x)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, block
, count
));
172 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
175 During this IO call it should be sure that both offset and
176 length are already aligned properly to sector boundaries.
178 if ((block
& mask
) | (count
& mask
))
180 D(bug("[ATA%02ld] cmd_Write32: offset or length not sector-aligned.\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
181 cmd_Invalid(io
, LIBBASE
);
185 block
>>= unit
->au_SectorShift
;
186 count
>>= unit
->au_SectorShift
;
189 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
))
190 && ((block
+ count
) > unit
->au_Capacity
))
192 bug("[ATA%02ld] cmd_Write32: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
,
193 block
, count
, unit
->au_Capacity
);
194 io
->io_Error
= IOERR_BADADDRESS
;
198 /* Call the Unit's access funtion */
199 io
->io_Error
= unit
->au_Write32(unit
, block
, count
,
200 IOStdReq(io
)->io_Data
, &cnt
);
202 IOStdReq(io
)->io_Actual
= cnt
;
207 NSCMD_TD_WRITE64, TD_WRITE64 implementation. Basically the same, just packs
208 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
210 static void cmd_Write64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
212 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
214 if (AF_Removable
== (unit
->au_Flags
& (AF_Removable
| AF_DiscPresent
)))
216 D(bug("[ATA%02ld] cmd_Write64: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit
->au_UnitNum
));
217 io
->io_Error
= TDERR_DiskChanged
;
222 UQUAD block
= IOStdReq(io
)->io_Offset
| (UQUAD
)(IOStdReq(io
)->io_Actual
) << 32;
223 ULONG count
= IOStdReq(io
)->io_Length
;
225 D(bug("[ATA%02ld] cmd_Write64(%08x-%08x, %08x)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, IOStdReq(io
)->io_Actual
, IOStdReq(io
)->io_Offset
, count
));
227 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
229 if ((block
& mask
) | (count
& mask
) | (count
==0))
231 D(bug("[ATA%02ld] cmd_Write64: offset or length not sector-aligned.\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
232 cmd_Invalid(io
, LIBBASE
);
236 block
>>= unit
->au_SectorShift
;
237 count
>>= unit
->au_SectorShift
;
241 If the sum of sector offset and the sector count doesn't overflow
242 the 28-bit LBA address, use 32-bit access for speed and simplicity.
243 Otherwise do the 48-bit LBA addressing.
245 if ((block
+ count
) < 0x0fffffff)
247 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
))
248 && ((block
+ count
) > unit
->au_Capacity
))
250 bug("[ATA%02ld] cmd_Write64: Requested block (%lx;%ld) outside disk range "
251 "(%lx)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, block
, count
, unit
->au_Capacity
);
252 io
->io_Error
= IOERR_BADADDRESS
;
255 io
->io_Error
= unit
->au_Write32(unit
, (ULONG
)(block
& 0x0fffffff),
256 count
, IOStdReq(io
)->io_Data
, &cnt
);
260 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
))
261 && ((block
+ count
) > unit
->au_Capacity48
))
263 bug("[ATA%02ld] cmd_Write64: Requested block (%lx:%08lx;%ld) outside disk "
264 "range (%lx:%08lx)\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
,
265 block
>>32, block
&0xfffffffful
,
266 count
, unit
->au_Capacity48
>>32,
267 unit
->au_Capacity48
& 0xfffffffful
);
268 io
->io_Error
= IOERR_BADADDRESS
;
272 io
->io_Error
= unit
->au_Write64(unit
, block
, count
,
273 IOStdReq(io
)->io_Data
, &cnt
);
275 IOStdReq(io
)->io_Actual
= cnt
;
280 /* use CMD_FLUSH to force all IO waiting commands to abort */
281 static void cmd_Flush(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
283 struct IORequest
*msg
;
284 struct ata_Bus
*bus
= ((struct ata_Unit
*)io
->io_Unit
)->au_Bus
;
286 D(bug("[ATA%02ld] cmd_Flush()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
290 while((msg
= (struct IORequest
*)GetMsg((struct MsgPort
*)bus
->ab_MsgPort
)))
292 msg
->io_Error
= IOERR_ABORTED
;
293 ReplyMsg((struct Message
*)msg
);
300 Internal command used to check whether the media in drive has been changed
301 since last call. If so, the handlers given by user are called.
303 static void cmd_TestChanged(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
305 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
306 struct IORequest
*msg
;
308 D(bug("[ATA%02ld] cmd_TestChanged()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
310 if ((unit
->au_XferModes
& AF_XFER_PACKET
) && (unit
->au_Flags
& AF_Removable
))
312 atapi_TestUnitOK(unit
);
313 if (unit
->au_Flags
& AF_DiscChanged
)
315 unit
->au_ChangeNum
++;
319 /* old-fashioned RemoveInt call first */
320 if (unit
->au_RemoveInt
)
321 Cause(unit
->au_RemoveInt
);
323 /* And now the whole list of possible calls */
324 ForeachNode(&unit
->au_SoftList
, msg
)
326 Cause((struct Interrupt
*)IOStdReq(msg
)->io_Data
);
329 unit
->au_Flags
&= ~AF_DiscChanged
;
336 static void cmd_Update(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
338 /* Do nothing now. In near future there should be drive cache flush though */
339 D(bug("[ATA%02ld] cmd_Update()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
342 static void cmd_Remove(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
344 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
346 D(bug("[ATA%02ld] cmd_Remove()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
348 if (unit
->au_RemoveInt
)
349 io
->io_Error
= TDERR_DriveInUse
;
351 unit
->au_RemoveInt
= IOStdReq(io
)->io_Data
;
354 static void cmd_ChangeNum(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
356 D(bug("[ATA%02ld] cmd_ChangeNum()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
358 IOStdReq(io
)->io_Actual
= ((struct ata_Unit
*)io
->io_Unit
)->au_ChangeNum
;
361 static void cmd_ChangeState(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
363 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
365 D(bug("[ATA%02ld] cmd_ChangeState()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
367 if (unit
->au_Flags
& AF_DiscPresent
)
368 IOStdReq(io
)->io_Actual
= 0;
370 IOStdReq(io
)->io_Actual
= 1;
372 D(bug("[ATA%02ld] cmd_ChangeState: Media %s\n", unit
->au_UnitNum
, IOStdReq(io
)->io_Actual
? "ABSENT" : "PRESENT"));
375 static void cmd_ProtStatus(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
377 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
379 D(bug("[ATA%02ld] cmd_ProtStatus()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
381 if (unit
->au_DevType
)
382 IOStdReq(io
)->io_Actual
= -1;
384 IOStdReq(io
)->io_Actual
= 0;
388 static void cmd_GetNumTracks(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
390 D(bug("[ATA%02ld] cmd_GetNumTracks()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
392 IOStdReq(io
)->io_Actual
= ((struct ata_Unit
*)io
->io_Unit
)->au_Cylinders
;
395 static void cmd_AddChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
397 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
399 D(bug("[ATA%02ld] cmd_AddChangeInt()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
402 AddHead(&unit
->au_SoftList
, (struct Node
*)io
);
405 io
->io_Flags
&= ~IOF_QUICK
;
406 unit
->au_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
409 static void cmd_RemChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
411 D(bug("[ATA%02ld] cmd_RemChangeInt()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
414 Remove((struct Node
*)io
);
418 static void cmd_Eject(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
420 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
422 D(bug("[ATA%02ld] cmd_Eject()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
424 IOStdReq(io
)->io_Error
= unit
->au_Eject(unit
);
425 cmd_TestChanged(io
, LIBBASE
);
428 static void cmd_GetGeometry(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
430 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
432 D(bug("[ATA%02ld] cmd_GetGeometry()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
434 if (IOStdReq(io
)->io_Length
== sizeof(struct DriveGeometry
))
436 struct DriveGeometry
*dg
= (struct DriveGeometry
*)IOStdReq(io
)->io_Data
;
438 dg
->dg_SectorSize
= 1 << unit
->au_SectorShift
;
440 if (unit
->au_Capacity48
!= 0)
442 if ((unit
->au_Capacity48
>> 32) != 0)
443 dg
->dg_TotalSectors
= 0xffffffff;
445 dg
->dg_TotalSectors
= unit
->au_Capacity48
;
448 dg
->dg_TotalSectors
= unit
->au_Capacity
;
450 dg
->dg_Cylinders
= unit
->au_Cylinders
;
451 dg
->dg_CylSectors
= unit
->au_Sectors
* unit
->au_Heads
;
452 dg
->dg_Heads
= unit
->au_Heads
;
453 dg
->dg_TrackSectors
= unit
->au_Sectors
;
454 dg
->dg_BufMemType
= MEMF_PUBLIC
;
455 dg
->dg_DeviceType
= unit
->au_DevType
;
456 if (dg
->dg_DeviceType
!= DG_DIRECT_ACCESS
)
457 dg
->dg_Flags
= (unit
->au_Flags
& AF_Removable
) ? DGF_REMOVABLE
: 0;
462 IOStdReq(io
)->io_Actual
= sizeof(struct DriveGeometry
);
464 else if (IOStdReq(io
)->io_Length
== 514)
466 CopyMemQuick(unit
->au_Drive
, IOStdReq(io
)->io_Data
, 512);
468 else io
->io_Error
= TDERR_NotSpecified
;
471 static void cmd_DirectScsi(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
473 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
475 D(bug("[ATA%02ld] cmd_DirectScsi()\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
477 IOStdReq(io
)->io_Actual
= sizeof(struct SCSICmd
);
478 if (unit
->au_XferModes
& AF_XFER_PACKET
)
480 io
->io_Error
= unit
->au_DirectSCSI(unit
, (struct SCSICmd
*)IOStdReq(io
)->io_Data
);
482 else if (unit
->au_DevType
== DG_DIRECT_ACCESS
)
484 io
->io_Error
= SCSIEmu(unit
, (struct SCSICmd
*)IOStdReq(io
)->io_Data
);
486 else io
->io_Error
= IOERR_BADADDRESS
;
489 //-----------------------------------------------------------------------------
492 command translation tables - used to call proper IO functions.
495 #define N_TD_READ64 0
496 #define N_TD_WRITE64 1
497 #define N_TD_SEEK64 2
498 #define N_TD_FORMAT64 3
500 typedef void (*mapfunc
)(struct IORequest
*, LIBBASETYPEPTR
);
502 static mapfunc
const map64
[]= {
503 [N_TD_READ64
] = cmd_Read64
,
504 [N_TD_WRITE64
] = cmd_Write64
,
505 [N_TD_SEEK64
] = cmd_Reset
,
506 [N_TD_FORMAT64
] = cmd_Write64
509 static mapfunc
const map32
[] = {
510 [CMD_INVALID
] = cmd_Invalid
,
511 [CMD_RESET
] = cmd_Reset
,
512 [CMD_READ
] = cmd_Read32
,
513 [CMD_WRITE
] = cmd_Write32
,
514 [CMD_UPDATE
] = cmd_Update
,
515 [CMD_CLEAR
] = cmd_Reset
,
516 [CMD_STOP
] = cmd_Reset
,
517 [CMD_START
] = cmd_Reset
,
518 [CMD_FLUSH
] = cmd_Flush
,
519 [TD_MOTOR
] = cmd_Reset
,
520 [TD_SEEK
] = cmd_Reset
,
521 [TD_FORMAT
] = cmd_Write32
,
522 [TD_REMOVE
] = cmd_Remove
,
523 [TD_CHANGENUM
] = cmd_ChangeNum
,
524 [TD_CHANGESTATE
]= cmd_ChangeState
,
525 [TD_PROTSTATUS
] = cmd_ProtStatus
,
526 [TD_RAWREAD
] = cmd_Invalid
,
527 [TD_RAWWRITE
] = cmd_Invalid
,
528 [TD_GETNUMTRACKS
] = cmd_GetNumTracks
,
529 [TD_ADDCHANGEINT
] = cmd_AddChangeInt
,
530 [TD_REMCHANGEINT
] = cmd_RemChangeInt
,
531 [TD_GETGEOMETRY
]= cmd_GetGeometry
,
532 [TD_EJECT
] = cmd_Eject
,
533 [TD_READ64
] = cmd_Read64
,
534 [TD_WRITE64
] = cmd_Write64
,
535 [TD_SEEK64
] = cmd_Reset
,
536 [TD_FORMAT64
] = cmd_Write64
,
537 [HD_SCSICMD
] = cmd_DirectScsi
,
538 [HD_SCSICMD
+1] = cmd_TestChanged
,
541 static UWORD
const NSDSupported
[] = {
577 Do proper IO actions depending on the request. It's called from the bus
578 tasks and from BeginIO in case of immediate commands.
580 static void HandleIO(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
584 /* Handle few commands directly here */
585 switch (io
->io_Command
)
588 New Style Devices query. Introduce self as trackdisk and provide list of
591 case NSCMD_DEVICEQUERY
:
593 struct NSDeviceQueryResult
*nsdq
= (struct NSDeviceQueryResult
*)IOStdReq(io
)->io_Data
;
594 nsdq
->DevQueryFormat
= 0;
595 nsdq
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
596 nsdq
->DeviceType
= NSDEVTYPE_TRACKDISK
;
597 nsdq
->DeviceSubType
= 0;
598 nsdq
->SupportedCommands
= (UWORD
*)NSDSupported
;
600 IOStdReq(io
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
604 New Style Devices report here the 'NSTY' - only if such value is
605 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
608 case TD_GETDRIVETYPE
:
609 IOStdReq(io
)->io_Actual
= DRIVE_NEWSTYLE
;
613 Call all other commands using the command pointer tables for 32- and
614 64-bit accesses. If requested function is defined call it, otherwise
615 make the function cmd_Invalid.
618 if (io
->io_Command
<= (HD_SCSICMD
+1))
620 if (map32
[io
->io_Command
])
621 map32
[io
->io_Command
](io
, LIBBASE
);
623 cmd_Invalid(io
, LIBBASE
);
625 else if (io
->io_Command
>= NSCMD_TD_READ64
&& io
->io_Command
<= NSCMD_TD_FORMAT64
)
627 if (map64
[io
->io_Command
- NSCMD_TD_READ64
])
628 map64
[io
->io_Command
- NSCMD_TD_READ64
](io
, LIBBASE
);
630 cmd_Invalid(io
, LIBBASE
);
632 else cmd_Invalid(io
, LIBBASE
);
638 static const ULONG IMMEDIATE_COMMANDS
= 0x803ff1e3; // 10000000001111111111000111100011
640 /* See whether the command can be done quick */
641 static BOOL
isSlow(ULONG comm
)
643 BOOL slow
= TRUE
; /* Assume always slow command */
645 /* For commands with numbers <= 31 check the mask */
648 if (IMMEDIATE_COMMANDS
& (1 << comm
))
651 else if (comm
== NSCMD_TD_SEEK64
) slow
= FALSE
;
657 Try to do IO commands. All commands which require talking with ata devices
658 will be handled slow, that is they will be passed to bus task which will
659 execute them as soon as hardware will be free.
661 AROS_LH1(void, BeginIO
,
662 AROS_LHA(struct IORequest
*, io
, A1
),
663 LIBBASETYPEPTR
, LIBBASE
, 5, ata
)
667 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
669 io
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
671 /* Disable interrupts for a while to modify message flags */
674 D(bug("[ATA%02ld] BeginIO: Executing IO Command %lx\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
, io
->io_Command
));
677 If the command is not-immediate, or presence of disc is still unknown,
678 let the bus task do the job.
680 if (isSlow(io
->io_Command
))
682 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
| UNITF_INTASK
;
683 io
->io_Flags
&= ~IOF_QUICK
;
686 /* Put the message to the bus */
687 PutMsg(unit
->au_Bus
->ab_MsgPort
, (struct Message
*)io
);
691 D(bug("[ATA%02ld] Fast command\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
693 /* Immediate command. Mark unit as active and do the command directly */
694 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
;
696 HandleIO(io
, LIBBASE
);
698 unit
->au_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
701 If the command was not intended to be immediate and it was not the
702 TD_ADDCHANGEINT, reply to confirm command execution now.
704 if (!(io
->io_Flags
& IOF_QUICK
) && (io
->io_Command
!= TD_ADDCHANGEINT
))
706 ReplyMsg((struct Message
*)io
);
710 D(bug("[ATA%02ld] BeginIO: Done\n", ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
714 AROS_LH1(LONG
, AbortIO
,
715 AROS_LHA(struct IORequest
*, io
, A1
),
716 LIBBASETYPEPTR
, LIBBASE
, 6, ata
)
720 /* Cannot Abort IO */
726 AROS_LH1(ULONG
, GetRdskLba
,
727 AROS_LHA(struct IORequest
*, io
, A1
),
728 LIBBASETYPEPTR
, LIBBASE
, 7, ata
)
737 AROS_LH1(ULONG
, GetBlkSize
,
738 AROS_LHA(struct IORequest
*, io
, A1
),
739 LIBBASETYPEPTR
, LIBBASE
, 8, ata
)
743 return Unit(io
)->au_SectorShift
;
749 * The daemon of ata.device first opens all ATAPI devices and then enters
750 * endless loop. Every 2 seconds it tells ATAPI units to check the media
751 * presence. In case of any state change they will rise user-specified
753 * The check is done by sending HD_SCSICMD+1 command (internal testchanged
754 * command). ATAPI units should already handle the command further.
756 void DaemonCode(struct ataBase
*ATABase
)
758 struct IORequest
*timer
; // timer
762 D(bug("[ATA**] You woke up DAEMON\n"));
765 * Prepare message ports and timer.device's request
767 timer
= ata_OpenTimer(ATABase
);
770 D(bug("[ATA++] Failed to open timer!\n"));
773 Signal(ATABase
->daemonParent
, SIGF_SINGLE
);
777 /* Calibrate 400ns delay */
778 if (!ata_Calibrate(timer
, ATABase
))
780 ata_CloseTimer(timer
);
782 Signal(ATABase
->daemonParent
, SIGF_SINGLE
);
786 /* This also signals that we have initialized successfully */
787 ATABase
->ata_Daemon
= FindTask(NULL
);
788 Signal(ATABase
->daemonParent
, SIGF_SINGLE
);
790 D(bug("[ATA++] Starting sweep medium presence detection\n"));
798 * call separate IORequest for every ATAPI device
799 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
800 * FIXME: This is not a very nice approach in terms of performance.
801 * This inserts own command into command queue every 2 seconds, so
802 * this would give periodic performance drops under high loads.
803 * It would be much better if unit tasks ping their devices by themselves,
804 * when idle. This would also save us from lots of headaches with dealing
805 * with list of these requests. Additionally i start disliking all these
810 struct IOStdReq
*ios
;
812 DB2(bug("[ATA++] Detecting media presence\n"));
813 ObtainSemaphore(&ATABase
->DaemonSem
);
815 ForeachNode(&ATABase
->Daemon_ios
, ios
)
817 /* Using the request will clobber its Node. Save links. */
818 struct Node
*s
= ios
->io_Message
.mn_Node
.ln_Succ
;
819 struct Node
*p
= ios
->io_Message
.mn_Node
.ln_Pred
;
821 DoIO((struct IORequest
*)ios
);
823 ios
->io_Message
.mn_Node
.ln_Succ
= s
;
824 ios
->io_Message
.mn_Node
.ln_Pred
= p
;
827 ReleaseSemaphore(&ATABase
->DaemonSem
);
831 * And then hide and wait for 1 second
833 DB2(bug("[ATA++] 1 second delay, timer 0x%p...\n", timer
));
834 sigs
= ata_WaitTO(timer
, 1, 0, SIGBREAKF_CTRL_C
);
836 DB2(bug("[ATA++] Delay completed\n"));
840 D(bug("[ATA++] Daemon quits\n"));
842 ata_CloseTimer(timer
);
845 Signal(ATABase
->daemonParent
, SIGF_SINGLE
);
849 Bus task body. It doesn't really do much. It receives simply all IORequests
850 in endless loop and calls proper handling function. The IO is Semaphore-
851 protected within a bus.
853 void BusTaskCode(struct ata_Bus
*bus
, struct ataBase
*ATABase
)
857 struct IORequest
*msg
;
858 struct ata_Unit
*unit
;
860 DINIT(bug("[ATA**] Task started (bus: %u)\n", bus
->ab_BusNum
));
862 bus
->ab_Timer
= ata_OpenTimer(ATABase
);
864 /* Get the signal used for sleeping */
865 bus
->ab_Task
= FindTask(0);
866 bus
->ab_SleepySignal
= AllocSignal(-1);
867 /* Failed to get it? Use SIGBREAKB_CTRL_E instead */
868 if (bus
->ab_SleepySignal
< 0)
869 bus
->ab_SleepySignal
= SIGBREAKB_CTRL_E
;
871 sig
= 1L << bus
->ab_MsgPort
->mp_SigBit
;
873 for (iter
= 0; iter
< MAX_BUSUNITS
; ++iter
)
875 DINIT(bug("[ATA**] Device %u type %d\n", iter
, bus
->ab_Dev
[iter
]));
877 if (bus
->ab_Dev
[iter
] > DEV_UNKNOWN
)
879 unit
= OOP_NewObject(ATABase
->unitClass
, NULL
, NULL
);
882 ata_init_unit(bus
, unit
, iter
);
883 if (ata_setup_unit(bus
, unit
))
886 * Add unit to the bus.
887 * At this point it becomes visible to OpenDevice().
889 bus
->ab_Units
[iter
] = unit
;
891 if (unit
->au_XferModes
& AF_XFER_PACKET
)
893 ata_RegisterVolume(0, 0, unit
);
895 /* For ATAPI device we also submit media presence detection request */
896 unit
->DaemonReq
= (struct IOStdReq
*)CreateIORequest(ATABase
->DaemonPort
, sizeof(struct IOStdReq
));
900 * We don't want to keep stalled open count of 1, so we
901 * don't call OpenDevice() here. Instead we fill in the needed
904 unit
->DaemonReq
->io_Device
= &ATABase
->ata_Device
;
905 unit
->DaemonReq
->io_Unit
= &unit
->au_Unit
;
906 unit
->DaemonReq
->io_Command
= HD_SCSICMD
+1;
908 ObtainSemaphore(&ATABase
->DaemonSem
);
909 AddTail((struct List
*)&ATABase
->Daemon_ios
,
910 &unit
->DaemonReq
->io_Message
.mn_Node
);
911 ReleaseSemaphore(&ATABase
->DaemonSem
);
916 ata_RegisterVolume(0, unit
->au_Cylinders
- 1, unit
);
921 /* Destroy unit that couldn't be initialised */
922 OOP_DisposeObject((OOP_Object
*)unit
);
923 bus
->ab_Dev
[iter
] = DEV_NONE
;
929 D(bug("[ATA--] Bus %u scan finished\n", bus
->ab_BusNum
));
930 ReleaseSemaphore(&ATABase
->DetectionSem
);
932 /* Wait forever and process messages */
937 /* Even if you get new signal, do not process it until Unit is not active */
938 if (!(bus
->ab_Flags
& UNITF_ACTIVE
))
940 bus
->ab_Flags
|= UNITF_ACTIVE
;
942 /* Empty the request queue */
943 while ((msg
= (struct IORequest
*)GetMsg(bus
->ab_MsgPort
)))
946 HandleIO(msg
, ATABase
);
947 /* TD_ADDCHANGEINT doesn't require reply */
948 if (msg
->io_Command
!= TD_ADDCHANGEINT
)
950 ReplyMsg((struct Message
*)msg
);
954 bus
->ab_Flags
&= ~(UNITF_INTASK
| UNITF_ACTIVE
);