2 Copyright © 2004-2006, The AROS Development Team. All rights reserved
11 * ---------- ------------------ -------------------------------------------------------------------
12 * 2008-01-25 T. Wiszkowski Rebuilt, rearranged and partially fixed 60% of the code here
13 * Enabled implementation to scan for other PCI IDE controllers
14 * Implemented ATAPI Packet Support for both read and write
15 * Corrected ATAPI DMA handling
16 * Fixed major IDE enumeration bugs severely handicapping transfers with more than one controller
17 * Compacted source and implemented major ATA support procedure
18 * Improved DMA and Interrupt management
19 * Removed obsolete code
23 #include <aros/debug.h>
25 #include <exec/types.h>
26 #include <exec/exec.h>
27 #include <exec/resident.h>
28 #include <utility/utility.h>
29 #include <utility/tagitem.h>
34 #include <proto/exec.h>
35 #include <proto/oop.h>
39 //---------------------------IO Commands---------------------------------------
41 /* Invalid comand does nothing, complains only. */
42 static void cmd_Invalid(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
44 D(bug("[ATA] Invalid command %d for unit %04x\n", io
->io_Command
,
45 ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
46 io
->io_Error
= IOERR_NOCMD
;
49 /* Don't need to reset the drive? */
50 static void cmd_Reset(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
52 IOStdReq(io
)->io_Actual
= 0;
55 /* CMD_READ implementation */
56 static void cmd_Read32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
58 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
59 ULONG block
= IOStdReq(io
)->io_Offset
;
60 ULONG count
= IOStdReq(io
)->io_Length
;
61 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
64 During this IO call it should be sure that both offset and
65 length are already aligned properly to sector boundaries.
67 if ((block
& mask
) | (count
& mask
))
69 D(bug("[ATA] offset or length not sector-aligned.\n"));
70 cmd_Invalid(io
, LIBBASE
);
74 block
>>= unit
->au_SectorShift
;
75 count
>>= unit
->au_SectorShift
;
78 /* Call the Unit's access funtion */
79 io
->io_Error
= unit
->au_Read32(unit
, block
, count
,
80 IOStdReq(io
)->io_Data
, &cnt
);
82 IOStdReq(io
)->io_Actual
= cnt
;
87 NSCMD_TD_READ64, TD_READ64 implementation. Basically the same, just packs
88 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
90 static void cmd_Read64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
92 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
94 UQUAD block
= (UQUAD
)(IOStdReq(io
)->io_Offset
& 0xffffffff) |
95 ((UQUAD
)(IOStdReq(io
)->io_Actual
)) << 32;
96 ULONG count
= IOStdReq(io
)->io_Length
;
97 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
99 if ((block
& (UQUAD
)mask
) | (count
& mask
) | (count
== 0))
101 D(bug("[ATA] offset or length not sector-aligned.\n"));
102 cmd_Invalid(io
, LIBBASE
);
106 block
>>= unit
->au_SectorShift
;
107 count
>>= unit
->au_SectorShift
;
111 If the sum of sector offset and the sector count doesn't overflow
112 the 28-bit LBA address, use 32-bit access for speed and simplicity.
113 Otherwise do the 48-bit LBA addressing.
115 if ((block
+ count
) < 0x0fffffff)
116 io
->io_Error
= unit
->au_Read32(unit
, (ULONG
)(block
& 0x0fffffff), count
,
117 IOStdReq(io
)->io_Data
, &cnt
);
119 io
->io_Error
= unit
->au_Read64(unit
, block
, count
,
120 IOStdReq(io
)->io_Data
, &cnt
);
122 IOStdReq(io
)->io_Actual
= cnt
;
126 /* CMD_WRITE implementation */
127 static void cmd_Write32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
129 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
130 ULONG block
= IOStdReq(io
)->io_Offset
;
131 ULONG count
= IOStdReq(io
)->io_Length
;
132 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
135 During this IO call it should be sure that both offset and
136 length are already aligned properly to sector boundaries.
138 if ((block
& mask
) | (count
& mask
))
140 D(bug("[ATA] offset or length not sector-aligned.\n"));
141 cmd_Invalid(io
, LIBBASE
);
145 block
>>= unit
->au_SectorShift
;
146 count
>>= unit
->au_SectorShift
;
149 /* Call the Unit's access funtion */
150 io
->io_Error
= unit
->au_Write32(unit
, block
, count
,
151 IOStdReq(io
)->io_Data
, &cnt
);
153 IOStdReq(io
)->io_Actual
= cnt
;
158 NSCMD_TD_WRITE64, TD_WRITE64 implementation. Basically the same, just packs
159 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
161 static void cmd_Write64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
163 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
165 UQUAD block
= IOStdReq(io
)->io_Offset
| (UQUAD
)(IOStdReq(io
)->io_Actual
) << 32;
166 ULONG count
= IOStdReq(io
)->io_Length
;
167 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
169 if ((block
& mask
) | (count
& mask
) | (count
==0))
171 D(bug("[ATA] offset or length not sector-aligned.\n"));
172 cmd_Invalid(io
, LIBBASE
);
176 block
>>= unit
->au_SectorShift
;
177 count
>>= unit
->au_SectorShift
;
181 If the sum of sector offset and the sector count doesn't overflow
182 the 28-bit LBA address, use 32-bit access for speed and simplicity.
183 Otherwise do the 48-bit LBA addressing.
185 if ((block
+ count
) < 0x0fffffff)
186 io
->io_Error
= unit
->au_Write32(unit
, (ULONG
)(block
& 0x0fffffff), count
,
187 IOStdReq(io
)->io_Data
, &cnt
);
189 io
->io_Error
= unit
->au_Write64(unit
, block
, count
,
190 IOStdReq(io
)->io_Data
, &cnt
);
191 IOStdReq(io
)->io_Actual
= cnt
;
196 /* use CMD_FLUSH to force all IO waiting commands to abort */
197 static void cmd_Flush(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
199 struct IORequest
*msg
;
200 struct ata_Bus
*bus
= ((struct ata_Unit
*)io
->io_Unit
)->au_Bus
;
204 while((msg
= (struct IORequest
*)GetMsg((struct MsgPort
*)bus
->ab_MsgPort
)))
206 msg
->io_Error
= IOERR_ABORTED
;
207 ReplyMsg((struct Message
*)msg
);
214 Internal command used to check, whether the media in drive has been changed
215 since last call. If so, the handlers given by user are called.
217 static void cmd_TestChanged(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
219 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
222 It's impossible to check media status in ATA harddrives :)
224 if (unit
->au_XferModes
& AF_XFER_PACKET
)
226 /* Don't bother with nonremovable ATAPI units */
227 if (unit
->au_Flags
& AF_Removable
)
229 struct IORequest
*msg
;
232 /* Issue media check */
233 if ((sense
= atapi_TestUnitOK(unit
)))
236 Clear the unknown flag. We do know already, that there
239 unit
->au_Flags
&= ~AF_DiscPresenceUnknown
;
241 /* Media not present */
242 if (!(unit
->au_Flags
& AF_DiscPresent
))
245 Do status change since last call. Do almost
246 nothing. Clear the AF_Used flag as the drive cannot
247 be really used without media.
249 unit
->au_Flags
&= ~AF_Used
;
252 /* Clear the presence flag */
253 unit
->au_Flags
&= ~AF_DiscPresent
;
258 No more mystery, we know already that there is media in
259 drive. Clear this mysterious flag.
261 unit
->au_Flags
&= ~AF_DiscPresenceUnknown
;
264 if (unit
->au_Flags
& AF_DiscPresent
)
266 /* No status change. Do nothing */
269 /* Set the presence flag */
270 unit
->au_Flags
|= AF_DiscPresent
;
273 If CPU came here, there was a change in media presence status.
274 First, increase the number of changes to satisfy the curiousity
276 unit
->au_ChangeNum
++;
279 And tell the truth to the world :D
283 /* old-fashioned RemoveInt call first */
284 if (unit
->au_RemoveInt
)
285 Cause(unit
->au_RemoveInt
);
287 /* And now the whole list of possible calls */
288 ForeachNode(&unit
->au_SoftList
, msg
)
290 Cause((struct Interrupt
*)IOStdReq(msg
)->io_Data
);
296 unit
->au_Flags
&= ~AF_Used
;
299 static void cmd_Update(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
301 /* Do nothing now. In near future there should be drive cache flush though */
304 static void cmd_Remove(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
306 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
308 if (unit
->au_RemoveInt
)
309 io
->io_Error
= TDERR_DriveInUse
;
311 unit
->au_RemoveInt
= IOStdReq(io
)->io_Data
;
314 static void cmd_ChangeNum(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
316 IOStdReq(io
)->io_Actual
= ((struct ata_Unit
*)io
->io_Unit
)->au_ChangeNum
;
319 static void cmd_ChangeState(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
321 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
323 if (unit
->au_Flags
& AF_DiscPresent
)
324 IOStdReq(io
)->io_Actual
= 0;
326 IOStdReq(io
)->io_Actual
= 1;
329 static void cmd_ProtStatus(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
331 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
333 if (unit
->au_DevType
)
334 IOStdReq(io
)->io_Actual
= -1;
336 IOStdReq(io
)->io_Actual
= 0;
340 static void cmd_GetNumTracks(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
342 IOStdReq(io
)->io_Actual
= ((struct ata_Unit
*)io
->io_Unit
)->au_Cylinders
;
345 static void cmd_AddChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
347 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
350 AddHead(&unit
->au_SoftList
, (struct Node
*)io
);
353 io
->io_Flags
&= ~IOF_QUICK
;
354 unit
->au_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
357 static void cmd_RemChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
360 Remove((struct Node
*)io
);
364 static void cmd_Eject(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
366 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
368 IOStdReq(io
)->io_Error
= unit
->au_Eject(unit
);
371 static void cmd_GetGeometry(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
373 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
375 if (IOStdReq(io
)->io_Length
== sizeof(struct DriveGeometry
))
377 struct DriveGeometry
*dg
= (struct DriveGeometry
*)IOStdReq(io
)->io_Data
;
379 dg
->dg_SectorSize
= 1 << unit
->au_SectorShift
;
381 if (unit
->au_Capacity48
> unit
->au_Capacity
) {
382 if ((unit
->au_Capacity48
>> 32) != 0)
383 dg
->dg_TotalSectors
= 0xffffffff;
385 dg
->dg_TotalSectors
= unit
->au_Capacity48
;
387 else dg
->dg_TotalSectors
= unit
->au_Capacity
;
389 dg
->dg_Cylinders
= unit
->au_Cylinders
;
390 dg
->dg_CylSectors
= unit
->au_Sectors
* unit
->au_Heads
;
391 dg
->dg_Heads
= unit
->au_Heads
;
392 dg
->dg_TrackSectors
= unit
->au_Sectors
;
393 dg
->dg_BufMemType
= MEMF_PUBLIC
;
394 dg
->dg_DeviceType
= unit
->au_DevType
;
395 dg
->dg_Flags
= (unit
->au_Flags
& AF_Removable
) ? DGF_REMOVABLE
: 0;
398 IOStdReq(io
)->io_Actual
= sizeof(struct DriveGeometry
);
400 else if (IOStdReq(io
)->io_Length
== 514)
402 CopyMemQuick(unit
->au_Drive
, IOStdReq(io
)->io_Data
, 512);
404 else io
->io_Error
= TDERR_NotSpecified
;
407 static void cmd_DirectScsi(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
409 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
411 IOStdReq(io
)->io_Actual
= sizeof(struct SCSICmd
);
412 if (unit
->au_XferModes
& AF_XFER_PACKET
)
414 io
->io_Error
= unit
->au_DirectSCSI(unit
, (struct SCSICmd
*)IOStdReq(io
)->io_Data
);
416 else io
->io_Error
= IOERR_BADADDRESS
;
419 //-----------------------------------------------------------------------------
422 command translation tables - used to call proper IO functions.
425 #define N_TD_READ64 0
426 #define N_TD_WRITE64 1
427 #define N_TD_SEEK64 2
428 #define N_TD_FORMAT64 3
430 static void (*map64
[])(struct IORequest
*, LIBBASETYPEPTR
) = {
431 [N_TD_READ64
] = cmd_Read64
,
432 [N_TD_WRITE64
] = cmd_Write64
,
433 [N_TD_SEEK64
] = cmd_Reset
,
434 [N_TD_FORMAT64
] = cmd_Write64
437 static void (*map32
[])(struct IORequest
*, LIBBASETYPEPTR
) = {
438 [CMD_INVALID
] = cmd_Invalid
,
439 [CMD_RESET
] = cmd_Reset
,
440 [CMD_READ
] = cmd_Read32
,
441 [CMD_WRITE
] = cmd_Write32
,
442 [CMD_UPDATE
] = cmd_Update
,
443 [CMD_CLEAR
] = cmd_Reset
,
444 [CMD_STOP
] = cmd_Reset
,
445 [CMD_START
] = cmd_Reset
,
446 [CMD_FLUSH
] = cmd_Flush
,
447 [TD_MOTOR
] = cmd_Reset
,
448 [TD_SEEK
] = cmd_Reset
,
449 [TD_FORMAT
] = cmd_Write32
,
450 [TD_REMOVE
] = cmd_Remove
,
451 [TD_CHANGENUM
] = cmd_ChangeNum
,
452 [TD_CHANGESTATE
]= cmd_ChangeState
,
453 [TD_PROTSTATUS
] = cmd_ProtStatus
,
454 [TD_RAWREAD
] = cmd_Invalid
,
455 [TD_RAWWRITE
] = cmd_Invalid
,
456 [TD_GETNUMTRACKS
] = cmd_GetNumTracks
,
457 [TD_ADDCHANGEINT
] = cmd_AddChangeInt
,
458 [TD_REMCHANGEINT
] = cmd_RemChangeInt
,
459 [TD_GETGEOMETRY
]= cmd_GetGeometry
,
460 [TD_EJECT
] = cmd_Eject
,
461 [TD_READ64
] = cmd_Read64
,
462 [TD_WRITE64
] = cmd_Write64
,
463 [TD_SEEK64
] = cmd_Reset
,
464 [TD_FORMAT64
] = cmd_Write64
,
465 [HD_SCSICMD
] = cmd_DirectScsi
,
466 [HD_SCSICMD
+1] = cmd_TestChanged
,
469 static const UWORD NSDSupported
[] = {
505 Do proper IO actions depending on the request. It's called from the bus
506 tasks and from BeginIO in case of immediate commands.
508 static void HandleIO(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
512 /* Handle few commands directly here */
513 switch (io
->io_Command
)
516 New Style Devices query. Introduce self as trackdisk and provide list of
519 case NSCMD_DEVICEQUERY
:
521 struct NSDeviceQueryResult
*nsdq
= (struct NSDeviceQueryResult
*)IOStdReq(io
)->io_Data
;
522 nsdq
->DevQueryFormat
= 0;
523 nsdq
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
524 nsdq
->DeviceType
= NSDEVTYPE_TRACKDISK
;
525 nsdq
->DeviceSubType
= 0;
526 nsdq
->SupportedCommands
= (UWORD
*)NSDSupported
;
528 IOStdReq(io
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
532 New Style Devices report here the 'NSTY' - only if such value is
533 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
536 case TD_GETDRIVETYPE
:
537 IOStdReq(io
)->io_Actual
= DRIVE_NEWSTYLE
;
541 Call all other commands using the command pointer tables for 32- and
542 64-bit accesses. If requested function is defined call it, otherwise
543 make the function cmd_Invalid.
546 if (io
->io_Command
<= (HD_SCSICMD
+1))
548 if (map32
[io
->io_Command
])
549 map32
[io
->io_Command
](io
, LIBBASE
);
551 cmd_Invalid(io
, LIBBASE
);
553 else if (io
->io_Command
>= NSCMD_TD_READ64
&& io
->io_Command
<= NSCMD_TD_FORMAT64
)
555 if (map64
[io
->io_Command
- NSCMD_TD_READ64
])
556 map64
[io
->io_Command
- NSCMD_TD_READ64
](io
, LIBBASE
);
558 cmd_Invalid(io
, LIBBASE
);
560 else cmd_Invalid(io
, LIBBASE
);
566 static const ULONG IMMEDIATE_COMMANDS
= 0x803ff1e3; // 10000000001111111111000111100011
568 /* See whether the command can be done quick */
569 BOOL
isSlow(ULONG comm
)
571 BOOL slow
= TRUE
; /* Assume alwasy slow command */
573 /* For commands with numbers <= 31 check the mask */
576 if (IMMEDIATE_COMMANDS
& (1 << comm
))
579 else if (comm
== NSCMD_TD_SEEK64
) slow
= FALSE
;
585 Try to do IO commands. All commands which require talking with ata devices
586 will be handled slow, that is they will be passed to bus task which will
587 execute them as soon as hardware will be free.
589 AROS_LH1(void, BeginIO
,
590 AROS_LHA(struct IORequest
*, io
, A1
),
591 LIBBASETYPEPTR
, LIBBASE
, 5, ata
)
595 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
597 io
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
599 /* Disable interrupts for a while to modify message flags */
602 D(bug("[>>ATA] Executing IO Command %lx\n", io
->io_Command
));
605 If the command is not-immediate, or presence of disc is still unknown,
606 let the bus task do the job.
608 if (isSlow(io
->io_Command
) || (unit
->au_Flags
& AF_DiscPresenceUnknown
))
610 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
| UNITF_INTASK
;
611 io
->io_Flags
&= ~IOF_QUICK
;
614 /* Put the message to the bus */
615 PutMsg(unit
->au_Bus
->ab_MsgPort
, (struct Message
*)io
);
619 /* Immediate command. Mark unit as active and do the command directly */
620 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
;
622 HandleIO(io
, LIBBASE
);
624 unit
->au_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
627 If the command was not intended to be immediate and it was not the
628 TD_ADDCHANGEINT, reply to confirm command execution now.
630 if (!(io
->io_Flags
& IOF_QUICK
) && (io
->io_Command
!= TD_ADDCHANGEINT
))
632 ReplyMsg((struct Message
*)io
);
636 D(bug("[ATA>>] Done\n"));
640 AROS_LH1(LONG
, AbortIO
,
641 AROS_LHA(struct IORequest
*, io
, A1
),
642 LIBBASETYPEPTR
, LIBBASE
, 6, ata
)
646 /* Cannot Abort IO */
652 AROS_LH1(ULONG
, GetRdskLba
,
653 AROS_LHA(struct IORequest
*, io
, A1
),
654 LIBBASETYPEPTR
, LIBBASE
, 7, ata
)
658 return Unit(io
)->au_RDBSector
;
663 AROS_LH1(ULONG
, GetBlkSize
,
664 AROS_LHA(struct IORequest
*, io
, A1
),
665 LIBBASETYPEPTR
, LIBBASE
, 8, ata
)
669 return Unit(io
)->au_SectorShift
;
675 The daemon of ata.device first opens all ATAPI devices and then enters
676 endless loop. Every 3 seconds it tells ATAPI units to check the media
677 presence. In case of any state change they will rise user-specified
680 static void DaemonCode(LIBBASETYPEPTR LIBBASE
);
682 /* Create the daemon task */
683 int ata_InitDaemonTask(LIBBASETYPEPTR LIBBASE
)
688 struct TagItem tags
[] = {
689 { TASKTAG_ARG1
, (IPTR
)LIBBASE
},
693 /* Get some memory */
694 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
695 ml
= AllocMem(sizeof(struct MemList
) + sizeof(struct MemEntry
), MEMF_PUBLIC
| MEMF_CLEAR
);
699 UBYTE
*sp
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
701 t
->tc_SPUpper
= sp
+ STACK_SIZE
;
702 t
->tc_SPReg
= (UBYTE
*)t
->tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
704 ml
->ml_NumEntries
= 2;
705 ml
->ml_ME
[0].me_Addr
= t
;
706 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
707 ml
->ml_ME
[1].me_Addr
= sp
;
708 ml
->ml_ME
[1].me_Length
= STACK_SIZE
;
710 NEWLIST(&t
->tc_MemEntry
);
711 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
713 t
->tc_Node
.ln_Name
= "ATA.daemon";
714 t
->tc_Node
.ln_Type
= NT_TASK
;
715 t
->tc_Node
.ln_Pri
= TASK_PRI
- 1; /* The daemon should have a little bit lower Pri as handler tasks */
717 LIBBASE
->ata_Daemon
= t
;
719 NewAddTask(t
, DaemonCode
, NULL
, (struct TagItem
*)&tags
);
726 * The daemon tries to send HD_SCSICMD+1 command (internal testchanged
727 * command) to all ATAPI devices in the system. They should already handle
728 * the command further.
730 void DaemonCode(LIBBASETYPEPTR LIBBASE
)
732 struct MsgPort
*mp
; // Message port used with timer.device
733 struct MsgPort
*myport
; // Message port used with ata.device
734 struct timerequest
*tr
; // timer's time request message
735 struct IOStdReq
*ios
[64]; // Placeholer for unit messages
739 D(bug("[ATA**] You woke up DAEMON\n"));
742 * Prepare message ports and timer.device's request
744 mp
= CreateMsgPort();
745 myport
= CreateMsgPort();
746 tr
= (struct timerequest
*)CreateIORequest(mp
, sizeof(struct timerequest
));
747 bus
= (struct ata_Bus
*)LIBBASE
->ata_Buses
.mlh_Head
;
750 * grab all buses, see if there is an atapi cdrom connected or anything alike
751 * TODO: good thing to consider putting extra code here for future hotplug support *if any*
753 while (bus
->ab_Node
.mln_Succ
!= NULL
)
756 D(bug("[ATA++] Checking bus %d\n", b
));
758 for (d
=0; d
< MAX_UNIT
; d
++)
763 D(bug("[ATA++] Unit %d is of type %x\n", (b
<<1)+d
, bus
->ab_Dev
[d
]));
765 if (bus
->ab_Dev
[d
] >= DEV_ATAPI
)
768 * Atapi device found. Create IOStdReq for it
770 ios
[count
] = (struct IOStdReq
*) CreateIORequest(myport
, sizeof(struct IOStdReq
));
772 ios
[count
]->io_Command
= HD_SCSICMD
+ 1;
775 * And force OpenDevice call. Don't use direct call as it's unsafe
776 * and not nice at all.
778 * so THIS is an OpenDevice().....
780 D(bug("[ATA++] Opening ATAPI device, unit %d\n", (b
<<1)|d
));
782 AROS_LCA(struct IORequest
*, (struct IORequest
*)(ios
[count
]), A1
),
783 AROS_LCA(ULONG
, (b
<< 1) | d
, D0
),
784 AROS_LCA(ULONG
, 0, D1
),
785 LIBBASETYPEPTR
, LIBBASE
, 1, ata
);
788 * increase amount of ATAPI devices in system
794 * INFO: we are only handling up to 64 atapi devices here
796 if (count
== sizeof(ios
) / sizeof(*ios
))
800 bus
= (struct ata_Bus
*)bus
->ab_Node
.mln_Succ
;
803 D(bug("[ATA++] Starting sweep medium presence detection\n"));
808 * Ok, open the timer.device
810 OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tr
, 0);
818 * call separate IORequest for every ATAPI device
819 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
821 D(bug("[ATA++] Detecting media presence\n"));
822 for (b
=0; b
< count
; b
++)
823 DoIO((struct IORequest
*)ios
[b
]);
826 * And then hide and wait ;)
828 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
829 tr
->tr_time
.tv_secs
= 3;
830 tr
->tr_time
.tv_micro
= 0;
831 DoIO((struct IORequest
*)tr
);
837 * Well, when there are no ATAPI device, daemon is useless. Say goodbay and quit then
839 D(bug("[%s] Deamon useless (no ATAPI devices in system). Bye\n",FindTask(NULL
)->tc_Node
.ln_Name
));
840 DeleteMsgPort(myport
);
842 DeleteIORequest((struct IORequest
*)tr
);
846 static void TaskCode(struct ata_Bus
*);
847 static void ata_Interrupt(HIDDT_IRQ_Handler
*, HIDDT_IRQ_HwInfo
*);
848 static void ata_Timeout(HIDDT_IRQ_Handler
*, HIDDT_IRQ_HwInfo
*);
851 * Make a task for given bus alive.
853 int ata_InitBusTask(struct ata_Bus
*bus
)
858 struct TagItem tags
[] = {
859 { TASKTAG_ARG1
, (IPTR
)bus
},
864 Need some memory. I don't know however, wheter it wouldn't be better
865 to take some RAM from device's memory pool.
867 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
868 ml
= AllocMem(sizeof(struct MemList
) + 2*sizeof(struct MemEntry
), MEMF_PUBLIC
| MEMF_CLEAR
);
872 /* Setup stack and put the pointer to the bus as the only parameter */
873 UBYTE
*sp
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
875 t
->tc_SPUpper
= sp
+ STACK_SIZE
;
876 t
->tc_SPReg
= (UBYTE
*)t
->tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
878 /* Message port receiving all the IO requests */
879 bus
->ab_MsgPort
= AllocMem(sizeof(struct MsgPort
), MEMF_PUBLIC
| MEMF_CLEAR
);
880 NEWLIST(&bus
->ab_MsgPort
->mp_MsgList
);
881 bus
->ab_MsgPort
->mp_Node
.ln_Type
= NT_MSGPORT
;
882 bus
->ab_MsgPort
->mp_Flags
= PA_SIGNAL
;
883 bus
->ab_MsgPort
->mp_SigBit
= SIGBREAKB_CTRL_F
;
884 bus
->ab_MsgPort
->mp_SigTask
= t
;
885 bus
->ab_MsgPort
->mp_Node
.ln_Name
= "ATA[PI] Subsystem";
888 /* Tell the System, which memory regions are to be freed upon a task completion */
889 ml
->ml_NumEntries
= 3;
890 ml
->ml_ME
[0].me_Addr
= t
;
891 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
892 ml
->ml_ME
[1].me_Addr
= sp
;
893 ml
->ml_ME
[1].me_Length
= STACK_SIZE
;
894 ml
->ml_ME
[2].me_Addr
= bus
->ab_MsgPort
;
895 ml
->ml_ME
[2].me_Length
= sizeof(struct MsgPort
);
897 NEWLIST(&t
->tc_MemEntry
);
898 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
900 t
->tc_Node
.ln_Name
= "ATA[PI] Subsystem";
901 t
->tc_Node
.ln_Type
= NT_TASK
;
902 t
->tc_Node
.ln_Pri
= TASK_PRI
;
906 /* Wake up the task */
907 NewAddTask(t
, TaskCode
, NULL
, (struct TagItem
*)&tags
);
913 static int CreateInterrupt(struct ata_Bus
*bus
)
915 struct OOP_Object
*o
;
918 HIDDT_IRQ_Handler
*timeout_irq
= AllocPooled(bus
->ab_Base
->ata_MemPool
, sizeof(HIDDT_IRQ_Handler
));
920 if (bus
->ab_IntHandler
&& timeout_irq
)
923 Prepare nice interrupt for our bus. Even if interrupt sharing is enabled,
924 it should work quite well
926 bus
->ab_IntHandler
->h_Node
.ln_Pri
= 10;
927 bus
->ab_IntHandler
->h_Node
.ln_Name
= bus
->ab_Task
->tc_Node
.ln_Name
;
928 bus
->ab_IntHandler
->h_Code
= ata_Interrupt
;
929 bus
->ab_IntHandler
->h_Data
= bus
;
931 timeout_irq
->h_Node
.ln_Pri
= 0;
932 timeout_irq
->h_Node
.ln_Name
= bus
->ab_Task
->tc_Node
.ln_Name
;
933 timeout_irq
->h_Code
= ata_Timeout
;
934 timeout_irq
->h_Data
= bus
;
936 o
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
939 struct pHidd_IRQ_AddHandler __msg__
= {
940 mID
: OOP_GetMethodID(IID_Hidd_IRQ
, moHidd_IRQ_AddHandler
),
941 handlerinfo
: bus
->ab_IntHandler
,
945 if (OOP_DoMethod(o
, (OOP_Msg
)msg
))
947 msg
->handlerinfo
= timeout_irq
;
948 msg
->id
= vHidd_IRQ_Timer
;
950 if (OOP_DoMethod(o
, (OOP_Msg
)msg
))
958 OOP_DisposeObject(o
);
966 Bus task body. It doesn't really do much. It recives simply all IORequests
967 in endless lopp and calls proper handling function. The IO is Semaphore-
968 protected within a bus.
970 static void TaskCode(struct ata_Bus
*bus
)
974 struct IORequest
*msg
;
976 D(bug("[ATA**] Task started (IO: 0x%x)\n", bus
->ab_Port
));
979 * Prepare timer.device in case some IO commands will try to wait using it
980 * instead of busy loop delays.
982 bus
->ab_TimerMP
= CreateMsgPort();
983 bus
->ab_TimerIO
= (struct timerequest
*)
984 CreateIORequest(bus
->ab_TimerMP
, sizeof(struct timerequest
));
986 /* Get the signal used for sleeping */
987 bus
->ab_SleepySignal
= AllocSignal(-1);
988 /* Failed to get it? Use SIGBREAKB_CTRL_E instead */
989 if (bus
->ab_SleepySignal
< 0)
990 bus
->ab_SleepySignal
= SIGBREAKB_CTRL_E
;
992 if (!CreateInterrupt(bus
))
994 D(bug("[%s] Something wrong with creating interrupt?\n",
995 bus
->ab_Task
->tc_Node
.ln_Name
));
998 OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)bus
->ab_TimerIO
, 0);
1000 sig
= 1L << bus
->ab_MsgPort
->mp_SigBit
;
1002 for (iter
=0; iter
<MAX_UNIT
; ++iter
)
1004 if (TRUE
== ata_setup_unit(bus
, iter
))
1006 if (bus
->ab_Units
[iter
]->au_XferModes
& AF_XFER_PACKET
)
1007 AddVolume(0, 0, bus
->ab_Units
[iter
]);
1009 AddVolume(0, bus
->ab_Units
[iter
]->au_Capacity
, bus
->ab_Units
[iter
]);
1014 /* Wait forever and process messages */
1019 /* Even if you get new signal, do not process it until Unit is not active */
1020 if (!(bus
->ab_Flags
& UNITF_ACTIVE
))
1022 bus
->ab_Flags
|= UNITF_ACTIVE
;
1024 /* Empty the request queue */
1025 while ((msg
= (struct IORequest
*)GetMsg(bus
->ab_MsgPort
)))
1028 ObtainSemaphore(&bus
->ab_Lock
);
1029 HandleIO(msg
, bus
->ab_Base
);
1030 ReleaseSemaphore(&bus
->ab_Lock
);
1031 /* TD_ADDCHANGEINT doesn't require reply */
1032 if (msg
->io_Command
!= TD_ADDCHANGEINT
)
1034 ReplyMsg((struct Message
*)msg
);
1038 bus
->ab_Flags
&= ~(UNITF_INTASK
| UNITF_ACTIVE
);
1043 static void ata_Interrupt(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
1045 struct ata_Bus
*bus
= (struct ata_Bus
*)irq
->h_Data
;
1048 Signal(bus
->ab_Task
, 1L << bus
->ab_SleepySignal
);
1049 D(bug("[ATA ] Got Intrq\n"));
1052 static void ata_Timeout(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
1054 struct ata_Bus
*bus
= (struct ata_Bus
*)irq
->h_Data
;
1056 if (bus
->ab_Timeout
> 0)
1060 if (!bus
->ab_Timeout
)
1062 D(bug("[ATA ] ERROR: Command timeout expired\n"));
1063 Signal(bus
->ab_Task
, SIGBREAKF_CTRL_C
);