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
20 * 2008-03-30 T. Wiszkowski Added workaround for interrupt collision handling; fixed SATA in LEGACY mode.
21 * nForce and Intel SATA chipsets should now be operational.
22 * 2008-04-03 T. Wiszkowski Fixed IRQ flood issue, eliminated and reduced obsolete / redundant code
23 * 2008-04-05 T. Wiszkowski Improved IRQ management
24 * 2008-04-07 T. Wiszkowski Changed bus timeout mechanism
25 * 2008-04-20 T. Wiszkowski Corrected the flaw in drive identification routines leading to ocassional system hangups
29 #include <aros/debug.h>
31 #include <exec/types.h>
32 #include <exec/exec.h>
33 #include <exec/resident.h>
34 #include <utility/utility.h>
35 #include <utility/tagitem.h>
40 #include <proto/exec.h>
41 #include <proto/oop.h>
45 //---------------------------IO Commands---------------------------------------
47 /* Invalid comand does nothing, complains only. */
48 static void cmd_Invalid(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
50 D(bug("[ATA] Invalid command %d for unit %04x\n", io
->io_Command
,
51 ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
52 io
->io_Error
= IOERR_NOCMD
;
55 /* Don't need to reset the drive? */
56 static void cmd_Reset(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
58 IOStdReq(io
)->io_Actual
= 0;
61 /* CMD_READ implementation */
62 static void cmd_Read32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
64 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
65 ULONG block
= IOStdReq(io
)->io_Offset
;
66 ULONG count
= IOStdReq(io
)->io_Length
;
67 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
70 During this IO call it should be sure that both offset and
71 length are already aligned properly to sector boundaries.
73 if ((block
& mask
) | (count
& mask
))
75 D(bug("[ATA] offset or length not sector-aligned.\n"));
76 cmd_Invalid(io
, LIBBASE
);
80 block
>>= unit
->au_SectorShift
;
81 count
>>= unit
->au_SectorShift
;
84 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity
))
86 bug("[ATA!!] Requested block (%lx;%ld) outside disk range (%lx)\n", block
, count
, unit
->au_Capacity
);
87 io
->io_Error
= IOERR_BADADDRESS
;
91 /* Call the Unit's access funtion */
92 io
->io_Error
= unit
->au_Read32(unit
, block
, count
,
93 IOStdReq(io
)->io_Data
, &cnt
);
95 IOStdReq(io
)->io_Actual
= cnt
;
100 NSCMD_TD_READ64, TD_READ64 implementation. Basically the same, just packs
101 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
103 static void cmd_Read64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
105 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
107 UQUAD block
= (UQUAD
)(IOStdReq(io
)->io_Offset
& 0xffffffff) |
108 ((UQUAD
)(IOStdReq(io
)->io_Actual
)) << 32;
109 ULONG count
= IOStdReq(io
)->io_Length
;
110 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
112 if ((block
& (UQUAD
)mask
) | (count
& mask
) | (count
== 0))
114 D(bug("[ATA] offset or length not sector-aligned.\n"));
115 cmd_Invalid(io
, LIBBASE
);
119 block
>>= unit
->au_SectorShift
;
120 count
>>= unit
->au_SectorShift
;
124 If the sum of sector offset and the sector count doesn't overflow
125 the 28-bit LBA address, use 32-bit access for speed and simplicity.
126 Otherwise do the 48-bit LBA addressing.
128 if ((block
+ count
) < 0x0fffffff)
130 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity
))
132 bug("[ATA!!] Requested block (%lx;%ld) outside disk range (%lx)\n", block
, count
, unit
->au_Capacity
);
133 io
->io_Error
= IOERR_BADADDRESS
;
136 io
->io_Error
= unit
->au_Read32(unit
, (ULONG
)(block
& 0x0fffffff), count
, IOStdReq(io
)->io_Data
, &cnt
);
140 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity48
))
142 bug("[ATA!!] Requested block (%lx:%08lx;%ld) outside disk range (%lx:%08lx;%ld)\n", block
>>32, block
&0xfffffffful
, count
, unit
->au_Capacity48
>>32, unit
->au_Capacity48
& 0xfffffffful
);
143 io
->io_Error
= IOERR_BADADDRESS
;
147 io
->io_Error
= unit
->au_Read64(unit
, block
, count
, IOStdReq(io
)->io_Data
, &cnt
);
150 IOStdReq(io
)->io_Actual
= cnt
;
154 /* CMD_WRITE implementation */
155 static void cmd_Write32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
157 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
158 ULONG block
= IOStdReq(io
)->io_Offset
;
159 ULONG count
= IOStdReq(io
)->io_Length
;
160 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
163 During this IO call it should be sure that both offset and
164 length are already aligned properly to sector boundaries.
166 if ((block
& mask
) | (count
& mask
))
168 D(bug("[ATA] offset or length not sector-aligned.\n"));
169 cmd_Invalid(io
, LIBBASE
);
173 block
>>= unit
->au_SectorShift
;
174 count
>>= unit
->au_SectorShift
;
177 /* Call the Unit's access funtion */
178 io
->io_Error
= unit
->au_Write32(unit
, block
, count
,
179 IOStdReq(io
)->io_Data
, &cnt
);
181 IOStdReq(io
)->io_Actual
= cnt
;
186 NSCMD_TD_WRITE64, TD_WRITE64 implementation. Basically the same, just packs
187 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
189 static void cmd_Write64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
191 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
193 UQUAD block
= IOStdReq(io
)->io_Offset
| (UQUAD
)(IOStdReq(io
)->io_Actual
) << 32;
194 ULONG count
= IOStdReq(io
)->io_Length
;
195 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
197 if ((block
& mask
) | (count
& mask
) | (count
==0))
199 D(bug("[ATA] offset or length not sector-aligned.\n"));
200 cmd_Invalid(io
, LIBBASE
);
204 block
>>= unit
->au_SectorShift
;
205 count
>>= unit
->au_SectorShift
;
209 If the sum of sector offset and the sector count doesn't overflow
210 the 28-bit LBA address, use 32-bit access for speed and simplicity.
211 Otherwise do the 48-bit LBA addressing.
213 if ((block
+ count
) < 0x0fffffff)
214 io
->io_Error
= unit
->au_Write32(unit
, (ULONG
)(block
& 0x0fffffff), count
,
215 IOStdReq(io
)->io_Data
, &cnt
);
217 io
->io_Error
= unit
->au_Write64(unit
, block
, count
,
218 IOStdReq(io
)->io_Data
, &cnt
);
219 IOStdReq(io
)->io_Actual
= cnt
;
224 /* use CMD_FLUSH to force all IO waiting commands to abort */
225 static void cmd_Flush(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
227 struct IORequest
*msg
;
228 struct ata_Bus
*bus
= ((struct ata_Unit
*)io
->io_Unit
)->au_Bus
;
232 while((msg
= (struct IORequest
*)GetMsg((struct MsgPort
*)bus
->ab_MsgPort
)))
234 msg
->io_Error
= IOERR_ABORTED
;
235 ReplyMsg((struct Message
*)msg
);
242 Internal command used to check, whether the media in drive has been changed
243 since last call. If so, the handlers given by user are called.
245 static void cmd_TestChanged(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
247 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
250 It's impossible to check media status in ATA harddrives :)
252 if (unit
->au_XferModes
& AF_XFER_PACKET
)
254 /* Don't bother with nonremovable ATAPI units */
255 if (unit
->au_Flags
& AF_Removable
)
257 struct IORequest
*msg
;
260 /* Issue media check */
261 if ((sense
= atapi_TestUnitOK(unit
)))
264 Clear the unknown flag. We do know already, that there
267 unit
->au_Flags
&= ~AF_DiscPresenceUnknown
;
269 /* Media not present */
270 if (!(unit
->au_Flags
& AF_DiscPresent
))
273 Do status change since last call. Do almost
274 nothing. Clear the AF_Used flag as the drive cannot
275 be really used without media.
277 unit
->au_Flags
&= ~AF_Used
;
280 /* Clear the presence flag */
281 unit
->au_Flags
&= ~AF_DiscPresent
;
286 No more mystery, we know already that there is media in
287 drive. Clear this mysterious flag.
289 unit
->au_Flags
&= ~AF_DiscPresenceUnknown
;
292 if (unit
->au_Flags
& AF_DiscPresent
)
294 /* No status change. Do nothing */
297 /* Set the presence flag */
298 unit
->au_Flags
|= AF_DiscPresent
;
301 If CPU came here, there was a change in media presence status.
302 First, increase the number of changes to satisfy the curiousity
304 unit
->au_ChangeNum
++;
307 And tell the truth to the world :D
311 /* old-fashioned RemoveInt call first */
312 if (unit
->au_RemoveInt
)
313 Cause(unit
->au_RemoveInt
);
315 /* And now the whole list of possible calls */
316 ForeachNode(&unit
->au_SoftList
, msg
)
318 Cause((struct Interrupt
*)IOStdReq(msg
)->io_Data
);
324 unit
->au_Flags
&= ~AF_Used
;
327 static void cmd_Update(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
329 /* Do nothing now. In near future there should be drive cache flush though */
332 static void cmd_Remove(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
334 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
336 if (unit
->au_RemoveInt
)
337 io
->io_Error
= TDERR_DriveInUse
;
339 unit
->au_RemoveInt
= IOStdReq(io
)->io_Data
;
342 static void cmd_ChangeNum(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
344 IOStdReq(io
)->io_Actual
= ((struct ata_Unit
*)io
->io_Unit
)->au_ChangeNum
;
347 static void cmd_ChangeState(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
349 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
351 if (unit
->au_Flags
& AF_DiscPresent
)
352 IOStdReq(io
)->io_Actual
= 0;
354 IOStdReq(io
)->io_Actual
= 1;
357 static void cmd_ProtStatus(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
359 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
361 if (unit
->au_DevType
)
362 IOStdReq(io
)->io_Actual
= -1;
364 IOStdReq(io
)->io_Actual
= 0;
368 static void cmd_GetNumTracks(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
370 IOStdReq(io
)->io_Actual
= ((struct ata_Unit
*)io
->io_Unit
)->au_Cylinders
;
373 static void cmd_AddChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
375 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
378 AddHead(&unit
->au_SoftList
, (struct Node
*)io
);
381 io
->io_Flags
&= ~IOF_QUICK
;
382 unit
->au_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
385 static void cmd_RemChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
388 Remove((struct Node
*)io
);
392 static void cmd_Eject(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
394 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
396 IOStdReq(io
)->io_Error
= unit
->au_Eject(unit
);
399 static void cmd_GetGeometry(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
401 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
403 if (IOStdReq(io
)->io_Length
== sizeof(struct DriveGeometry
))
405 struct DriveGeometry
*dg
= (struct DriveGeometry
*)IOStdReq(io
)->io_Data
;
407 dg
->dg_SectorSize
= 1 << unit
->au_SectorShift
;
409 if (unit
->au_Capacity48
> unit
->au_Capacity
) {
410 if ((unit
->au_Capacity48
>> 32) != 0)
411 dg
->dg_TotalSectors
= 0xffffffff;
413 dg
->dg_TotalSectors
= unit
->au_Capacity48
;
415 else dg
->dg_TotalSectors
= unit
->au_Capacity
;
417 dg
->dg_Cylinders
= unit
->au_Cylinders
;
418 dg
->dg_CylSectors
= unit
->au_Sectors
* unit
->au_Heads
;
419 dg
->dg_Heads
= unit
->au_Heads
;
420 dg
->dg_TrackSectors
= unit
->au_Sectors
;
421 dg
->dg_BufMemType
= MEMF_PUBLIC
;
422 dg
->dg_DeviceType
= unit
->au_DevType
;
423 dg
->dg_Flags
= (unit
->au_Flags
& AF_Removable
) ? DGF_REMOVABLE
: 0;
426 IOStdReq(io
)->io_Actual
= sizeof(struct DriveGeometry
);
428 else if (IOStdReq(io
)->io_Length
== 514)
430 CopyMemQuick(unit
->au_Drive
, IOStdReq(io
)->io_Data
, 512);
432 else io
->io_Error
= TDERR_NotSpecified
;
435 static void cmd_DirectScsi(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
437 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
439 IOStdReq(io
)->io_Actual
= sizeof(struct SCSICmd
);
440 if (unit
->au_XferModes
& AF_XFER_PACKET
)
442 io
->io_Error
= unit
->au_DirectSCSI(unit
, (struct SCSICmd
*)IOStdReq(io
)->io_Data
);
444 else io
->io_Error
= IOERR_BADADDRESS
;
447 //-----------------------------------------------------------------------------
450 command translation tables - used to call proper IO functions.
453 #define N_TD_READ64 0
454 #define N_TD_WRITE64 1
455 #define N_TD_SEEK64 2
456 #define N_TD_FORMAT64 3
458 static void (*map64
[])(struct IORequest
*, LIBBASETYPEPTR
) = {
459 [N_TD_READ64
] = cmd_Read64
,
460 [N_TD_WRITE64
] = cmd_Write64
,
461 [N_TD_SEEK64
] = cmd_Reset
,
462 [N_TD_FORMAT64
] = cmd_Write64
465 static void (*map32
[])(struct IORequest
*, LIBBASETYPEPTR
) = {
466 [CMD_INVALID
] = cmd_Invalid
,
467 [CMD_RESET
] = cmd_Reset
,
468 [CMD_READ
] = cmd_Read32
,
469 [CMD_WRITE
] = cmd_Write32
,
470 [CMD_UPDATE
] = cmd_Update
,
471 [CMD_CLEAR
] = cmd_Reset
,
472 [CMD_STOP
] = cmd_Reset
,
473 [CMD_START
] = cmd_Reset
,
474 [CMD_FLUSH
] = cmd_Flush
,
475 [TD_MOTOR
] = cmd_Reset
,
476 [TD_SEEK
] = cmd_Reset
,
477 [TD_FORMAT
] = cmd_Write32
,
478 [TD_REMOVE
] = cmd_Remove
,
479 [TD_CHANGENUM
] = cmd_ChangeNum
,
480 [TD_CHANGESTATE
]= cmd_ChangeState
,
481 [TD_PROTSTATUS
] = cmd_ProtStatus
,
482 [TD_RAWREAD
] = cmd_Invalid
,
483 [TD_RAWWRITE
] = cmd_Invalid
,
484 [TD_GETNUMTRACKS
] = cmd_GetNumTracks
,
485 [TD_ADDCHANGEINT
] = cmd_AddChangeInt
,
486 [TD_REMCHANGEINT
] = cmd_RemChangeInt
,
487 [TD_GETGEOMETRY
]= cmd_GetGeometry
,
488 [TD_EJECT
] = cmd_Eject
,
489 [TD_READ64
] = cmd_Read64
,
490 [TD_WRITE64
] = cmd_Write64
,
491 [TD_SEEK64
] = cmd_Reset
,
492 [TD_FORMAT64
] = cmd_Write64
,
493 [HD_SCSICMD
] = cmd_DirectScsi
,
494 [HD_SCSICMD
+1] = cmd_TestChanged
,
497 static const UWORD NSDSupported
[] = {
533 Do proper IO actions depending on the request. It's called from the bus
534 tasks and from BeginIO in case of immediate commands.
536 static void HandleIO(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
540 /* Handle few commands directly here */
541 switch (io
->io_Command
)
544 New Style Devices query. Introduce self as trackdisk and provide list of
547 case NSCMD_DEVICEQUERY
:
549 struct NSDeviceQueryResult
*nsdq
= (struct NSDeviceQueryResult
*)IOStdReq(io
)->io_Data
;
550 nsdq
->DevQueryFormat
= 0;
551 nsdq
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
552 nsdq
->DeviceType
= NSDEVTYPE_TRACKDISK
;
553 nsdq
->DeviceSubType
= 0;
554 nsdq
->SupportedCommands
= (UWORD
*)NSDSupported
;
556 IOStdReq(io
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
560 New Style Devices report here the 'NSTY' - only if such value is
561 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
564 case TD_GETDRIVETYPE
:
565 IOStdReq(io
)->io_Actual
= DRIVE_NEWSTYLE
;
569 Call all other commands using the command pointer tables for 32- and
570 64-bit accesses. If requested function is defined call it, otherwise
571 make the function cmd_Invalid.
574 if (io
->io_Command
<= (HD_SCSICMD
+1))
576 if (map32
[io
->io_Command
])
577 map32
[io
->io_Command
](io
, LIBBASE
);
579 cmd_Invalid(io
, LIBBASE
);
581 else if (io
->io_Command
>= NSCMD_TD_READ64
&& io
->io_Command
<= NSCMD_TD_FORMAT64
)
583 if (map64
[io
->io_Command
- NSCMD_TD_READ64
])
584 map64
[io
->io_Command
- NSCMD_TD_READ64
](io
, LIBBASE
);
586 cmd_Invalid(io
, LIBBASE
);
588 else cmd_Invalid(io
, LIBBASE
);
594 static const ULONG IMMEDIATE_COMMANDS
= 0x803ff1e3; // 10000000001111111111000111100011
596 /* See whether the command can be done quick */
597 BOOL
isSlow(ULONG comm
)
599 BOOL slow
= TRUE
; /* Assume alwasy slow command */
601 /* For commands with numbers <= 31 check the mask */
604 if (IMMEDIATE_COMMANDS
& (1 << comm
))
607 else if (comm
== NSCMD_TD_SEEK64
) slow
= FALSE
;
613 Try to do IO commands. All commands which require talking with ata devices
614 will be handled slow, that is they will be passed to bus task which will
615 execute them as soon as hardware will be free.
617 AROS_LH1(void, BeginIO
,
618 AROS_LHA(struct IORequest
*, io
, A1
),
619 LIBBASETYPEPTR
, LIBBASE
, 5, ata
)
623 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
625 io
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
627 /* Disable interrupts for a while to modify message flags */
630 D(bug("[>>ATA] Executing IO Command %lx\n", io
->io_Command
));
633 If the command is not-immediate, or presence of disc is still unknown,
634 let the bus task do the job.
636 if (isSlow(io
->io_Command
) || (unit
->au_Flags
& AF_DiscPresenceUnknown
))
638 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
| UNITF_INTASK
;
639 io
->io_Flags
&= ~IOF_QUICK
;
642 /* Put the message to the bus */
643 PutMsg(unit
->au_Bus
->ab_MsgPort
, (struct Message
*)io
);
647 /* Immediate command. Mark unit as active and do the command directly */
648 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
;
650 HandleIO(io
, LIBBASE
);
652 unit
->au_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
655 If the command was not intended to be immediate and it was not the
656 TD_ADDCHANGEINT, reply to confirm command execution now.
658 if (!(io
->io_Flags
& IOF_QUICK
) && (io
->io_Command
!= TD_ADDCHANGEINT
))
660 ReplyMsg((struct Message
*)io
);
664 D(bug("[ATA>>] Done\n"));
668 AROS_LH1(LONG
, AbortIO
,
669 AROS_LHA(struct IORequest
*, io
, A1
),
670 LIBBASETYPEPTR
, LIBBASE
, 6, ata
)
674 /* Cannot Abort IO */
680 AROS_LH1(ULONG
, GetRdskLba
,
681 AROS_LHA(struct IORequest
*, io
, A1
),
682 LIBBASETYPEPTR
, LIBBASE
, 7, ata
)
686 return Unit(io
)->au_RDBSector
;
691 AROS_LH1(ULONG
, GetBlkSize
,
692 AROS_LHA(struct IORequest
*, io
, A1
),
693 LIBBASETYPEPTR
, LIBBASE
, 8, ata
)
697 return Unit(io
)->au_SectorShift
;
703 The daemon of ata.device first opens all ATAPI devices and then enters
704 endless loop. Every 3 seconds it tells ATAPI units to check the media
705 presence. In case of any state change they will rise user-specified
708 static void DaemonCode(LIBBASETYPEPTR LIBBASE
);
710 /* Create the daemon task */
711 int ata_InitDaemonTask(LIBBASETYPEPTR LIBBASE
)
716 struct TagItem tags
[] = {
717 { TASKTAG_ARG1
, (IPTR
)LIBBASE
},
721 /* Get some memory */
722 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
723 ml
= AllocMem(sizeof(struct MemList
) + sizeof(struct MemEntry
), MEMF_PUBLIC
| MEMF_CLEAR
);
727 UBYTE
*sp
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
729 t
->tc_SPUpper
= sp
+ STACK_SIZE
;
730 t
->tc_SPReg
= (UBYTE
*)t
->tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
732 ml
->ml_NumEntries
= 2;
733 ml
->ml_ME
[0].me_Addr
= t
;
734 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
735 ml
->ml_ME
[1].me_Addr
= sp
;
736 ml
->ml_ME
[1].me_Length
= STACK_SIZE
;
738 NEWLIST(&t
->tc_MemEntry
);
739 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
741 t
->tc_Node
.ln_Name
= "ATA.daemon";
742 t
->tc_Node
.ln_Type
= NT_TASK
;
743 t
->tc_Node
.ln_Pri
= TASK_PRI
- 1; /* The daemon should have a little bit lower Pri as handler tasks */
745 LIBBASE
->ata_Daemon
= t
;
747 NewAddTask(t
, DaemonCode
, NULL
, (struct TagItem
*)&tags
);
754 * The daemon tries to send HD_SCSICMD+1 command (internal testchanged
755 * command) to all ATAPI devices in the system. They should already handle
756 * the command further.
758 void DaemonCode(LIBBASETYPEPTR LIBBASE
)
760 struct MsgPort
*mp
; // Message port used with timer.device
761 struct MsgPort
*myport
; // Message port used with ata.device
762 struct timerequest
*tr
; // timer's time request message
763 struct IOStdReq
*ios
[64]; // Placeholer for unit messages
767 D(bug("[ATA**] You woke up DAEMON\n"));
770 * Prepare message ports and timer.device's request
772 mp
= CreateMsgPort();
773 myport
= CreateMsgPort();
774 tr
= (struct timerequest
*)CreateIORequest(mp
, sizeof(struct timerequest
));
775 bus
= (struct ata_Bus
*)LIBBASE
->ata_Buses
.mlh_Head
;
778 * grab all buses, see if there is an atapi cdrom connected or anything alike
779 * TODO: good thing to consider putting extra code here for future hotplug support *if any*
781 while (bus
->ab_Node
.mln_Succ
!= NULL
)
784 D(bug("[ATA++] Checking bus %d\n", b
));
786 for (d
=0; d
< MAX_UNIT
; d
++)
791 D(bug("[ATA++] Unit %d is of type %x\n", (b
<<1)+d
, bus
->ab_Dev
[d
]));
793 if (bus
->ab_Dev
[d
] >= DEV_ATAPI
)
796 * Atapi device found. Create IOStdReq for it
798 ios
[count
] = (struct IOStdReq
*) CreateIORequest(myport
, sizeof(struct IOStdReq
));
800 ios
[count
]->io_Command
= HD_SCSICMD
+ 1;
803 * And force OpenDevice call. Don't use direct call as it's unsafe
804 * and not nice at all.
806 * so THIS is an OpenDevice().....
808 D(bug("[ATA++] Opening ATAPI device, unit %d\n", (b
<<1)|d
));
810 AROS_LCA(struct IORequest
*, (struct IORequest
*)(ios
[count
]), A1
),
811 AROS_LCA(ULONG
, (b
<< 1) | d
, D0
),
812 AROS_LCA(ULONG
, 0, D1
),
813 LIBBASETYPEPTR
, LIBBASE
, 1, ata
);
816 * increase amount of ATAPI devices in system
822 * INFO: we are only handling up to 64 atapi devices here
824 if (count
== sizeof(ios
) / sizeof(*ios
))
828 bus
= (struct ata_Bus
*)bus
->ab_Node
.mln_Succ
;
831 D(bug("[ATA++] Starting sweep medium presence detection\n"));
836 * Ok, open the timer.device
838 OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tr
, 0);
846 * call separate IORequest for every ATAPI device
847 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
851 D(bug("[ATA++] Detecting media presence\n"));
852 for (d
=0; d
< count
; d
++)
853 DoIO((struct IORequest
*)ios
[d
]);
857 * check / trigger all buses waiting for an irq
859 ForeachNode(&LIBBASE
->ata_Buses
, bus
)
861 if (bus
->ab_Timeout
>= 0)
863 if (0 > (--bus
->ab_Timeout
))
865 Signal(bus
->ab_Task
, SIGBREAKF_CTRL_C
);
871 * And then hide and wait for 1 second
873 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
874 tr
->tr_time
.tv_secs
= 1;
875 tr
->tr_time
.tv_micro
= 0;
876 DoIO((struct IORequest
*)tr
);
882 * Well, when there are no ATAPI device, daemon is useless. Say goodbay and quit then
884 D(bug("[%s] Deamon useless (no ATAPI devices in system). Bye\n",FindTask(NULL
)->tc_Node
.ln_Name
));
885 DeleteMsgPort(myport
);
887 DeleteIORequest((struct IORequest
*)tr
);
891 static void TaskCode(struct ata_Bus
*, struct Task
*);
892 static void ata_Interrupt(HIDDT_IRQ_Handler
*, HIDDT_IRQ_HwInfo
*);
895 * Make a task for given bus alive.
897 int ata_InitBusTask(struct ata_Bus
*bus
)
902 struct TagItem tags
[] = {
903 { TASKTAG_ARG1
, (IPTR
)bus
},
904 { TASKTAG_ARG2
, (IPTR
)FindTask(0) },
909 Need some memory. I don't know however, wheter it wouldn't be better
910 to take some RAM from device's memory pool.
912 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
913 ml
= AllocMem(sizeof(struct MemList
) + 2*sizeof(struct MemEntry
), MEMF_PUBLIC
| MEMF_CLEAR
);
917 /* Setup stack and put the pointer to the bus as the only parameter */
918 UBYTE
*sp
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
920 t
->tc_SPUpper
= sp
+ STACK_SIZE
;
921 t
->tc_SPReg
= (UBYTE
*)t
->tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
923 /* Message port receiving all the IO requests */
924 bus
->ab_MsgPort
= AllocMem(sizeof(struct MsgPort
), MEMF_PUBLIC
| MEMF_CLEAR
);
925 NEWLIST(&bus
->ab_MsgPort
->mp_MsgList
);
926 bus
->ab_MsgPort
->mp_Node
.ln_Type
= NT_MSGPORT
;
927 bus
->ab_MsgPort
->mp_Flags
= PA_SIGNAL
;
928 bus
->ab_MsgPort
->mp_SigBit
= SIGBREAKB_CTRL_F
;
929 bus
->ab_MsgPort
->mp_SigTask
= t
;
930 bus
->ab_MsgPort
->mp_Node
.ln_Name
= "ATA[PI] Subsystem";
933 /* Tell the System, which memory regions are to be freed upon a task completion */
934 ml
->ml_NumEntries
= 3;
935 ml
->ml_ME
[0].me_Addr
= t
;
936 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
937 ml
->ml_ME
[1].me_Addr
= sp
;
938 ml
->ml_ME
[1].me_Length
= STACK_SIZE
;
939 ml
->ml_ME
[2].me_Addr
= bus
->ab_MsgPort
;
940 ml
->ml_ME
[2].me_Length
= sizeof(struct MsgPort
);
942 NEWLIST(&t
->tc_MemEntry
);
943 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
945 t
->tc_Node
.ln_Name
= "ATA[PI] Subsystem";
946 t
->tc_Node
.ln_Type
= NT_TASK
;
947 t
->tc_Node
.ln_Pri
= TASK_PRI
;
951 /* Wake up the task */
952 NewAddTask(t
, TaskCode
, NULL
, (struct TagItem
*)&tags
);
953 Wait(SIGBREAKF_CTRL_C
);
959 static int CreateInterrupt(struct ata_Bus
*bus
)
961 struct OOP_Object
*o
;
964 if (bus
->ab_IntHandler
)
967 Prepare nice interrupt for our bus. Even if interrupt sharing is enabled,
968 it should work quite well
970 bus
->ab_IntHandler
->h_Node
.ln_Pri
= 10;
971 bus
->ab_IntHandler
->h_Node
.ln_Name
= bus
->ab_Task
->tc_Node
.ln_Name
;
972 bus
->ab_IntHandler
->h_Code
= ata_Interrupt
;
973 bus
->ab_IntHandler
->h_Data
= bus
;
975 o
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
978 struct pHidd_IRQ_AddHandler __msg__
= {
979 mID
: OOP_GetMethodID(IID_Hidd_IRQ
, moHidd_IRQ_AddHandler
),
980 handlerinfo
: bus
->ab_IntHandler
,
984 if (OOP_DoMethod(o
, (OOP_Msg
)msg
))
987 OOP_DisposeObject(o
);
995 Bus task body. It doesn't really do much. It recives simply all IORequests
996 in endless lopp and calls proper handling function. The IO is Semaphore-
997 protected within a bus.
999 static void TaskCode(struct ata_Bus
*bus
, struct Task
* parent
)
1003 struct IORequest
*msg
;
1005 D(bug("[ATA**] Task started (IO: 0x%x)\n", bus
->ab_Port
));
1007 /* Get the signal used for sleeping */
1008 bus
->ab_SleepySignal
= AllocSignal(-1);
1009 /* Failed to get it? Use SIGBREAKB_CTRL_E instead */
1010 if (bus
->ab_SleepySignal
< 0)
1011 bus
->ab_SleepySignal
= SIGBREAKB_CTRL_E
;
1013 if (!CreateInterrupt(bus
))
1015 D(bug("[%s] Something wrong with creating interrupt?\n",
1016 bus
->ab_Task
->tc_Node
.ln_Name
));
1019 sig
= 1L << bus
->ab_MsgPort
->mp_SigBit
;
1021 for (iter
=0; iter
<MAX_UNIT
; ++iter
)
1023 if (TRUE
== ata_setup_unit(bus
, iter
))
1025 if (bus
->ab_Units
[iter
]->au_XferModes
& AF_XFER_PACKET
)
1026 AddVolume(0, 0, bus
->ab_Units
[iter
]);
1028 AddVolume(0, bus
->ab_Units
[iter
]->au_Capacity
, bus
->ab_Units
[iter
]);
1032 Signal(parent
, SIGBREAKF_CTRL_C
);
1034 /* Wait forever and process messages */
1039 /* Even if you get new signal, do not process it until Unit is not active */
1040 if (!(bus
->ab_Flags
& UNITF_ACTIVE
))
1042 bus
->ab_Flags
|= UNITF_ACTIVE
;
1044 /* Empty the request queue */
1045 while ((msg
= (struct IORequest
*)GetMsg(bus
->ab_MsgPort
)))
1048 ObtainSemaphore(&bus
->ab_Lock
);
1049 HandleIO(msg
, bus
->ab_Base
);
1050 ReleaseSemaphore(&bus
->ab_Lock
);
1051 /* TD_ADDCHANGEINT doesn't require reply */
1052 if (msg
->io_Command
!= TD_ADDCHANGEINT
)
1054 ReplyMsg((struct Message
*)msg
);
1058 bus
->ab_Flags
&= ~(UNITF_INTASK
| UNITF_ACTIVE
);
1063 static void ata_Interrupt(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
1065 struct ata_Bus
*bus
= (struct ata_Bus
*)irq
->h_Data
;
1070 /* vim: set ts=4 sw=4 :*/