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
26 * 2008-05-11 T. Wiszkowski Remade the ata trannsfers altogether, corrected the pio/irq handling
27 * medium removal, device detection, bus management and much more
31 #include <aros/debug.h>
33 #include <exec/types.h>
34 #include <exec/exec.h>
35 #include <exec/resident.h>
36 #include <utility/utility.h>
37 #include <utility/tagitem.h>
42 #include <proto/exec.h>
43 #include <proto/oop.h>
47 //---------------------------IO Commands---------------------------------------
49 /* Invalid comand does nothing, complains only. */
50 static void cmd_Invalid(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
52 D(bug("[ATA] Invalid command %d for unit %04x\n", io
->io_Command
,
53 ((struct ata_Unit
*)io
->io_Unit
)->au_UnitNum
));
54 io
->io_Error
= IOERR_NOCMD
;
57 /* Don't need to reset the drive? */
58 static void cmd_Reset(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
60 IOStdReq(io
)->io_Actual
= 0;
63 /* CMD_READ implementation */
64 static void cmd_Read32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
66 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
67 ULONG block
= IOStdReq(io
)->io_Offset
;
68 ULONG count
= IOStdReq(io
)->io_Length
;
69 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
72 During this IO call it should be sure that both offset and
73 length are already aligned properly to sector boundaries.
75 if ((block
& mask
) | (count
& mask
))
77 D(bug("[ATA] offset or length not sector-aligned.\n"));
78 cmd_Invalid(io
, LIBBASE
);
82 block
>>= unit
->au_SectorShift
;
83 count
>>= unit
->au_SectorShift
;
86 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity
))
88 bug("[ATA!!] Requested block (%lx;%ld) outside disk range (%lx)\n", block
, count
, unit
->au_Capacity
);
89 io
->io_Error
= IOERR_BADADDRESS
;
93 /* Call the Unit's access funtion */
94 io
->io_Error
= unit
->au_Read32(unit
, block
, count
,
95 IOStdReq(io
)->io_Data
, &cnt
);
97 IOStdReq(io
)->io_Actual
= cnt
;
102 NSCMD_TD_READ64, TD_READ64 implementation. Basically the same, just packs
103 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
105 static void cmd_Read64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
107 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
109 UQUAD block
= (UQUAD
)(IOStdReq(io
)->io_Offset
& 0xffffffff) |
110 ((UQUAD
)(IOStdReq(io
)->io_Actual
)) << 32;
111 ULONG count
= IOStdReq(io
)->io_Length
;
112 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
114 if ((block
& (UQUAD
)mask
) | (count
& mask
) | (count
== 0))
116 D(bug("[ATA] offset or length not sector-aligned.\n"));
117 cmd_Invalid(io
, LIBBASE
);
121 block
>>= unit
->au_SectorShift
;
122 count
>>= unit
->au_SectorShift
;
126 If the sum of sector offset and the sector count doesn't overflow
127 the 28-bit LBA address, use 32-bit access for speed and simplicity.
128 Otherwise do the 48-bit LBA addressing.
130 if ((block
+ count
) < 0x0fffffff)
132 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity
))
134 bug("[ATA!!] Requested block (%lx;%ld) outside disk range (%lx)\n", block
, count
, unit
->au_Capacity
);
135 io
->io_Error
= IOERR_BADADDRESS
;
138 io
->io_Error
= unit
->au_Read32(unit
, (ULONG
)(block
& 0x0fffffff), count
, IOStdReq(io
)->io_Data
, &cnt
);
142 if ((0 == (unit
->au_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->au_Capacity48
))
144 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
);
145 io
->io_Error
= IOERR_BADADDRESS
;
149 io
->io_Error
= unit
->au_Read64(unit
, block
, count
, IOStdReq(io
)->io_Data
, &cnt
);
152 IOStdReq(io
)->io_Actual
= cnt
;
156 /* CMD_WRITE implementation */
157 static void cmd_Write32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
159 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
160 ULONG block
= IOStdReq(io
)->io_Offset
;
161 ULONG count
= IOStdReq(io
)->io_Length
;
162 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
165 During this IO call it should be sure that both offset and
166 length are already aligned properly to sector boundaries.
168 if ((block
& mask
) | (count
& mask
))
170 D(bug("[ATA] offset or length not sector-aligned.\n"));
171 cmd_Invalid(io
, LIBBASE
);
175 block
>>= unit
->au_SectorShift
;
176 count
>>= unit
->au_SectorShift
;
179 /* Call the Unit's access funtion */
180 io
->io_Error
= unit
->au_Write32(unit
, block
, count
,
181 IOStdReq(io
)->io_Data
, &cnt
);
183 IOStdReq(io
)->io_Actual
= cnt
;
188 NSCMD_TD_WRITE64, TD_WRITE64 implementation. Basically the same, just packs
189 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
191 static void cmd_Write64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
193 struct ata_Unit
*unit
= (struct ata_Unit
*)IOStdReq(io
)->io_Unit
;
195 UQUAD block
= IOStdReq(io
)->io_Offset
| (UQUAD
)(IOStdReq(io
)->io_Actual
) << 32;
196 ULONG count
= IOStdReq(io
)->io_Length
;
197 ULONG mask
= (1 << unit
->au_SectorShift
) - 1;
199 if ((block
& mask
) | (count
& mask
) | (count
==0))
201 D(bug("[ATA] offset or length not sector-aligned.\n"));
202 cmd_Invalid(io
, LIBBASE
);
206 block
>>= unit
->au_SectorShift
;
207 count
>>= unit
->au_SectorShift
;
211 If the sum of sector offset and the sector count doesn't overflow
212 the 28-bit LBA address, use 32-bit access for speed and simplicity.
213 Otherwise do the 48-bit LBA addressing.
215 if ((block
+ count
) < 0x0fffffff)
216 io
->io_Error
= unit
->au_Write32(unit
, (ULONG
)(block
& 0x0fffffff), count
,
217 IOStdReq(io
)->io_Data
, &cnt
);
219 io
->io_Error
= unit
->au_Write64(unit
, block
, count
,
220 IOStdReq(io
)->io_Data
, &cnt
);
221 IOStdReq(io
)->io_Actual
= cnt
;
226 /* use CMD_FLUSH to force all IO waiting commands to abort */
227 static void cmd_Flush(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
229 struct IORequest
*msg
;
230 struct ata_Bus
*bus
= ((struct ata_Unit
*)io
->io_Unit
)->au_Bus
;
234 while((msg
= (struct IORequest
*)GetMsg((struct MsgPort
*)bus
->ab_MsgPort
)))
236 msg
->io_Error
= IOERR_ABORTED
;
237 ReplyMsg((struct Message
*)msg
);
244 Internal command used to check, whether the media in drive has been changed
245 since last call. If so, the handlers given by user are called.
247 static void cmd_TestChanged(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
249 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
250 struct IORequest
*msg
;
252 if ((unit
->au_XferModes
& AF_XFER_PACKET
) && (unit
->au_Flags
& AF_Removable
))
254 atapi_TestUnitOK(unit
);
255 if (unit
->au_Flags
& AF_DiscChanged
)
257 unit
->au_ChangeNum
++;
261 /* old-fashioned RemoveInt call first */
262 if (unit
->au_RemoveInt
)
263 Cause(unit
->au_RemoveInt
);
265 /* And now the whole list of possible calls */
266 ForeachNode(&unit
->au_SoftList
, msg
)
268 Cause((struct Interrupt
*)IOStdReq(msg
)->io_Data
);
271 unit
->au_Flags
&= ~AF_DiscChanged
;
278 static void cmd_Update(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
280 /* Do nothing now. In near future there should be drive cache flush though */
283 static void cmd_Remove(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
285 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
287 if (unit
->au_RemoveInt
)
288 io
->io_Error
= TDERR_DriveInUse
;
290 unit
->au_RemoveInt
= IOStdReq(io
)->io_Data
;
293 static void cmd_ChangeNum(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
295 IOStdReq(io
)->io_Actual
= ((struct ata_Unit
*)io
->io_Unit
)->au_ChangeNum
;
298 static void cmd_ChangeState(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
300 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
302 if (unit
->au_Flags
& AF_DiscPresent
)
303 IOStdReq(io
)->io_Actual
= 0;
305 IOStdReq(io
)->io_Actual
= 1;
307 D(bug("[ATA%02lx] Media %s\n", unit
->au_UnitNum
, IOStdReq(io
)->io_Actual
? "ABSENT" : "PRESENT"));
310 static void cmd_ProtStatus(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
312 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
314 if (unit
->au_DevType
)
315 IOStdReq(io
)->io_Actual
= -1;
317 IOStdReq(io
)->io_Actual
= 0;
321 static void cmd_GetNumTracks(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
323 IOStdReq(io
)->io_Actual
= ((struct ata_Unit
*)io
->io_Unit
)->au_Cylinders
;
326 static void cmd_AddChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
328 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
331 AddHead(&unit
->au_SoftList
, (struct Node
*)io
);
334 io
->io_Flags
&= ~IOF_QUICK
;
335 unit
->au_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
338 static void cmd_RemChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
341 Remove((struct Node
*)io
);
345 static void cmd_Eject(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
347 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
349 IOStdReq(io
)->io_Error
= unit
->au_Eject(unit
);
352 static void cmd_GetGeometry(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
354 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
356 if (IOStdReq(io
)->io_Length
== sizeof(struct DriveGeometry
))
358 struct DriveGeometry
*dg
= (struct DriveGeometry
*)IOStdReq(io
)->io_Data
;
360 dg
->dg_SectorSize
= 1 << unit
->au_SectorShift
;
362 if (unit
->au_Capacity48
!= 0)
364 if ((unit
->au_Capacity48
>> 32) != 0)
365 dg
->dg_TotalSectors
= 0xffffffff;
367 dg
->dg_TotalSectors
= unit
->au_Capacity48
;
370 dg
->dg_TotalSectors
= unit
->au_Capacity
;
372 dg
->dg_Cylinders
= unit
->au_Cylinders
;
373 dg
->dg_CylSectors
= unit
->au_Sectors
* unit
->au_Heads
;
374 dg
->dg_Heads
= unit
->au_Heads
;
375 dg
->dg_TrackSectors
= unit
->au_Sectors
;
376 dg
->dg_BufMemType
= MEMF_PUBLIC
;
377 dg
->dg_DeviceType
= unit
->au_DevType
;
378 dg
->dg_Flags
= (unit
->au_Flags
& AF_Removable
) ? DGF_REMOVABLE
: 0;
381 IOStdReq(io
)->io_Actual
= sizeof(struct DriveGeometry
);
383 else if (IOStdReq(io
)->io_Length
== 514)
385 CopyMemQuick(unit
->au_Drive
, IOStdReq(io
)->io_Data
, 512);
387 else io
->io_Error
= TDERR_NotSpecified
;
390 static void cmd_DirectScsi(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
392 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
394 IOStdReq(io
)->io_Actual
= sizeof(struct SCSICmd
);
395 if (unit
->au_XferModes
& AF_XFER_PACKET
)
397 io
->io_Error
= unit
->au_DirectSCSI(unit
, (struct SCSICmd
*)IOStdReq(io
)->io_Data
);
399 else io
->io_Error
= IOERR_BADADDRESS
;
402 //-----------------------------------------------------------------------------
405 command translation tables - used to call proper IO functions.
408 #define N_TD_READ64 0
409 #define N_TD_WRITE64 1
410 #define N_TD_SEEK64 2
411 #define N_TD_FORMAT64 3
413 static void (*map64
[])(struct IORequest
*, LIBBASETYPEPTR
) = {
414 [N_TD_READ64
] = cmd_Read64
,
415 [N_TD_WRITE64
] = cmd_Write64
,
416 [N_TD_SEEK64
] = cmd_Reset
,
417 [N_TD_FORMAT64
] = cmd_Write64
420 static void (*map32
[])(struct IORequest
*, LIBBASETYPEPTR
) = {
421 [CMD_INVALID
] = cmd_Invalid
,
422 [CMD_RESET
] = cmd_Reset
,
423 [CMD_READ
] = cmd_Read32
,
424 [CMD_WRITE
] = cmd_Write32
,
425 [CMD_UPDATE
] = cmd_Update
,
426 [CMD_CLEAR
] = cmd_Reset
,
427 [CMD_STOP
] = cmd_Reset
,
428 [CMD_START
] = cmd_Reset
,
429 [CMD_FLUSH
] = cmd_Flush
,
430 [TD_MOTOR
] = cmd_Reset
,
431 [TD_SEEK
] = cmd_Reset
,
432 [TD_FORMAT
] = cmd_Write32
,
433 [TD_REMOVE
] = cmd_Remove
,
434 [TD_CHANGENUM
] = cmd_ChangeNum
,
435 [TD_CHANGESTATE
]= cmd_ChangeState
,
436 [TD_PROTSTATUS
] = cmd_ProtStatus
,
437 [TD_RAWREAD
] = cmd_Invalid
,
438 [TD_RAWWRITE
] = cmd_Invalid
,
439 [TD_GETNUMTRACKS
] = cmd_GetNumTracks
,
440 [TD_ADDCHANGEINT
] = cmd_AddChangeInt
,
441 [TD_REMCHANGEINT
] = cmd_RemChangeInt
,
442 [TD_GETGEOMETRY
]= cmd_GetGeometry
,
443 [TD_EJECT
] = cmd_Eject
,
444 [TD_READ64
] = cmd_Read64
,
445 [TD_WRITE64
] = cmd_Write64
,
446 [TD_SEEK64
] = cmd_Reset
,
447 [TD_FORMAT64
] = cmd_Write64
,
448 [HD_SCSICMD
] = cmd_DirectScsi
,
449 [HD_SCSICMD
+1] = cmd_TestChanged
,
452 static const UWORD NSDSupported
[] = {
488 Do proper IO actions depending on the request. It's called from the bus
489 tasks and from BeginIO in case of immediate commands.
491 static void HandleIO(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
495 /* Handle few commands directly here */
496 switch (io
->io_Command
)
499 New Style Devices query. Introduce self as trackdisk and provide list of
502 case NSCMD_DEVICEQUERY
:
504 struct NSDeviceQueryResult
*nsdq
= (struct NSDeviceQueryResult
*)IOStdReq(io
)->io_Data
;
505 nsdq
->DevQueryFormat
= 0;
506 nsdq
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
507 nsdq
->DeviceType
= NSDEVTYPE_TRACKDISK
;
508 nsdq
->DeviceSubType
= 0;
509 nsdq
->SupportedCommands
= (UWORD
*)NSDSupported
;
511 IOStdReq(io
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
515 New Style Devices report here the 'NSTY' - only if such value is
516 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
519 case TD_GETDRIVETYPE
:
520 IOStdReq(io
)->io_Actual
= DRIVE_NEWSTYLE
;
524 Call all other commands using the command pointer tables for 32- and
525 64-bit accesses. If requested function is defined call it, otherwise
526 make the function cmd_Invalid.
529 if (io
->io_Command
<= (HD_SCSICMD
+1))
531 if (map32
[io
->io_Command
])
532 map32
[io
->io_Command
](io
, LIBBASE
);
534 cmd_Invalid(io
, LIBBASE
);
536 else if (io
->io_Command
>= NSCMD_TD_READ64
&& io
->io_Command
<= NSCMD_TD_FORMAT64
)
538 if (map64
[io
->io_Command
- NSCMD_TD_READ64
])
539 map64
[io
->io_Command
- NSCMD_TD_READ64
](io
, LIBBASE
);
541 cmd_Invalid(io
, LIBBASE
);
543 else cmd_Invalid(io
, LIBBASE
);
549 static const ULONG IMMEDIATE_COMMANDS
= 0x803ff1e3; // 10000000001111111111000111100011
551 /* See whether the command can be done quick */
552 BOOL
isSlow(ULONG comm
)
554 BOOL slow
= TRUE
; /* Assume alwasy slow command */
556 /* For commands with numbers <= 31 check the mask */
559 if (IMMEDIATE_COMMANDS
& (1 << comm
))
562 else if (comm
== NSCMD_TD_SEEK64
) slow
= FALSE
;
568 Try to do IO commands. All commands which require talking with ata devices
569 will be handled slow, that is they will be passed to bus task which will
570 execute them as soon as hardware will be free.
572 AROS_LH1(void, BeginIO
,
573 AROS_LHA(struct IORequest
*, io
, A1
),
574 LIBBASETYPEPTR
, LIBBASE
, 5, ata
)
578 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
580 io
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
582 /* Disable interrupts for a while to modify message flags */
585 D(bug("[>>ATA] Executing IO Command %lx\n", io
->io_Command
));
588 If the command is not-immediate, or presence of disc is still unknown,
589 let the bus task do the job.
591 if (isSlow(io
->io_Command
))
593 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
| UNITF_INTASK
;
594 io
->io_Flags
&= ~IOF_QUICK
;
597 /* Put the message to the bus */
598 PutMsg(unit
->au_Bus
->ab_MsgPort
, (struct Message
*)io
);
602 /* Immediate command. Mark unit as active and do the command directly */
603 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
;
605 HandleIO(io
, LIBBASE
);
607 unit
->au_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
610 If the command was not intended to be immediate and it was not the
611 TD_ADDCHANGEINT, reply to confirm command execution now.
613 if (!(io
->io_Flags
& IOF_QUICK
) && (io
->io_Command
!= TD_ADDCHANGEINT
))
615 ReplyMsg((struct Message
*)io
);
619 D(bug("[ATA>>] Done\n"));
623 AROS_LH1(LONG
, AbortIO
,
624 AROS_LHA(struct IORequest
*, io
, A1
),
625 LIBBASETYPEPTR
, LIBBASE
, 6, ata
)
629 /* Cannot Abort IO */
635 AROS_LH1(ULONG
, GetRdskLba
,
636 AROS_LHA(struct IORequest
*, io
, A1
),
637 LIBBASETYPEPTR
, LIBBASE
, 7, ata
)
646 AROS_LH1(ULONG
, GetBlkSize
,
647 AROS_LHA(struct IORequest
*, io
, A1
),
648 LIBBASETYPEPTR
, LIBBASE
, 8, ata
)
652 return Unit(io
)->au_SectorShift
;
658 The daemon of ata.device first opens all ATAPI devices and then enters
659 endless loop. Every 3 seconds it tells ATAPI units to check the media
660 presence. In case of any state change they will rise user-specified
663 static void DaemonCode(LIBBASETYPEPTR LIBBASE
);
665 /* Create the daemon task */
666 int ata_InitDaemonTask(LIBBASETYPEPTR LIBBASE
)
671 struct TagItem tags
[] = {
672 { TASKTAG_ARG1
, (IPTR
)LIBBASE
},
676 /* Get some memory */
677 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
678 ml
= AllocMem(sizeof(struct MemList
) + sizeof(struct MemEntry
), MEMF_PUBLIC
| MEMF_CLEAR
);
682 UBYTE
*sp
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
684 t
->tc_SPUpper
= sp
+ STACK_SIZE
;
685 t
->tc_SPReg
= (UBYTE
*)t
->tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
687 ml
->ml_NumEntries
= 2;
688 ml
->ml_ME
[0].me_Addr
= t
;
689 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
690 ml
->ml_ME
[1].me_Addr
= sp
;
691 ml
->ml_ME
[1].me_Length
= STACK_SIZE
;
693 NEWLIST(&t
->tc_MemEntry
);
694 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
696 t
->tc_Node
.ln_Name
= "ATA.daemon";
697 t
->tc_Node
.ln_Type
= NT_TASK
;
698 t
->tc_Node
.ln_Pri
= TASK_PRI
- 1; /* The daemon should have a little bit lower Pri as handler tasks */
700 LIBBASE
->ata_Daemon
= t
;
702 NewAddTask(t
, DaemonCode
, NULL
, (struct TagItem
*)&tags
);
709 * The daemon tries to send HD_SCSICMD+1 command (internal testchanged
710 * command) to all ATAPI devices in the system. They should already handle
711 * the command further.
713 void DaemonCode(LIBBASETYPEPTR LIBBASE
)
715 struct MsgPort
*mp
; // Message port used with timer.device
716 struct MsgPort
*myport
; // Message port used with ata.device
717 struct timerequest
*tr
; // timer's time request message
718 struct IOStdReq
*ios
[64]; // Placeholer for unit messages
722 D(bug("[ATA**] You woke up DAEMON\n"));
725 * Prepare message ports and timer.device's request
727 mp
= CreateMsgPort();
728 myport
= CreateMsgPort();
729 tr
= (struct timerequest
*)CreateIORequest(mp
, sizeof(struct timerequest
));
730 bus
= (struct ata_Bus
*)LIBBASE
->ata_Buses
.mlh_Head
;
733 * grab all buses, see if there is an atapi cdrom connected or anything alike
734 * TODO: good thing to consider putting extra code here for future hotplug support *if any*
736 while (bus
->ab_Node
.mln_Succ
!= NULL
)
739 D(bug("[ATA++] Checking bus %d\n", b
));
741 for (d
=0; d
< MAX_UNIT
; d
++)
746 D(bug("[ATA++] Unit %d is of type %x\n", (b
<<1)+d
, bus
->ab_Dev
[d
]));
748 if (bus
->ab_Dev
[d
] >= DEV_ATAPI
)
751 * Atapi device found. Create IOStdReq for it
753 ios
[count
] = (struct IOStdReq
*) CreateIORequest(myport
, sizeof(struct IOStdReq
));
755 ios
[count
]->io_Command
= HD_SCSICMD
+ 1;
758 * And force OpenDevice call. Don't use direct call as it's unsafe
759 * and not nice at all.
761 * so THIS is an OpenDevice().....
763 D(bug("[ATA++] Opening ATAPI device, unit %d\n", (b
<<1)|d
));
765 AROS_LCA(struct IORequest
*, (struct IORequest
*)(ios
[count
]), A1
),
766 AROS_LCA(ULONG
, (b
<< 1) | d
, D0
),
767 AROS_LCA(ULONG
, 0, D1
),
768 LIBBASETYPEPTR
, LIBBASE
, 1, ata
);
771 * increase amount of ATAPI devices in system
777 * INFO: we are only handling up to 64 atapi devices here
779 if (count
== sizeof(ios
) / sizeof(*ios
))
783 bus
= (struct ata_Bus
*)bus
->ab_Node
.mln_Succ
;
786 D(bug("[ATA++] Starting sweep medium presence detection\n"));
791 * Ok, open the timer.device
793 OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tr
, 0);
801 * call separate IORequest for every ATAPI device
802 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
806 D(bug("[ATA++] Detecting media presence\n"));
807 for (d
=0; d
< count
; d
++)
808 DoIO((struct IORequest
*)ios
[d
]);
812 * check / trigger all buses waiting for an irq
814 ForeachNode(&LIBBASE
->ata_Buses
, bus
)
816 if (bus
->ab_Timeout
>= 0)
818 if (0 > (--bus
->ab_Timeout
))
820 Signal(bus
->ab_Task
, SIGBREAKF_CTRL_C
);
826 * And then hide and wait for 1 second
828 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
829 tr
->tr_time
.tv_secs
= 1;
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
*, struct Task
*, struct SignalSemaphore
*);
847 static void ata_Interrupt(HIDDT_IRQ_Handler
*, HIDDT_IRQ_HwInfo
*);
850 * Make a task for given bus alive.
852 int ata_InitBusTask(struct ata_Bus
*bus
, struct SignalSemaphore
*ready
)
857 struct TagItem tags
[] = {
858 { TASKTAG_ARG1
, (IPTR
)bus
},
859 { TASKTAG_ARG2
, (IPTR
)FindTask(0) },
860 { TASKTAG_ARG3
, (IPTR
)ready
},
865 Need some memory. I don't know however, wheter it wouldn't be better
866 to take some RAM from device's memory pool.
868 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
869 ml
= AllocMem(sizeof(struct MemList
) + 2*sizeof(struct MemEntry
), MEMF_PUBLIC
| MEMF_CLEAR
);
873 /* Setup stack and put the pointer to the bus as the only parameter */
874 UBYTE
*sp
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
876 t
->tc_SPUpper
= sp
+ STACK_SIZE
;
877 t
->tc_SPReg
= (UBYTE
*)t
->tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
879 /* Message port receiving all the IO requests */
880 bus
->ab_MsgPort
= AllocMem(sizeof(struct MsgPort
), MEMF_PUBLIC
| MEMF_CLEAR
);
881 NEWLIST(&bus
->ab_MsgPort
->mp_MsgList
);
882 bus
->ab_MsgPort
->mp_Node
.ln_Type
= NT_MSGPORT
;
883 bus
->ab_MsgPort
->mp_Flags
= PA_SIGNAL
;
884 bus
->ab_MsgPort
->mp_SigBit
= SIGBREAKB_CTRL_F
;
885 bus
->ab_MsgPort
->mp_SigTask
= t
;
886 bus
->ab_MsgPort
->mp_Node
.ln_Name
= "ATA[PI] Subsystem";
889 /* Tell the System, which memory regions are to be freed upon a task completion */
890 ml
->ml_NumEntries
= 3;
891 ml
->ml_ME
[0].me_Addr
= t
;
892 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
893 ml
->ml_ME
[1].me_Addr
= sp
;
894 ml
->ml_ME
[1].me_Length
= STACK_SIZE
;
895 ml
->ml_ME
[2].me_Addr
= bus
->ab_MsgPort
;
896 ml
->ml_ME
[2].me_Length
= sizeof(struct MsgPort
);
898 NEWLIST(&t
->tc_MemEntry
);
899 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
901 t
->tc_Node
.ln_Name
= "ATA[PI] Subsystem";
902 t
->tc_Node
.ln_Type
= NT_TASK
;
903 t
->tc_Node
.ln_Pri
= TASK_PRI
;
905 /* Wake up the task */
906 NewAddTask(t
, TaskCode
, NULL
, (struct TagItem
*)&tags
);
907 Wait(SIGBREAKF_CTRL_C
);
913 static int CreateInterrupt(struct ata_Bus
*bus
)
915 struct OOP_Object
*o
;
918 if (bus
->ab_IntHandler
)
921 Prepare nice interrupt for our bus. Even if interrupt sharing is enabled,
922 it should work quite well
924 bus
->ab_IntHandler
->h_Node
.ln_Pri
= 10;
925 bus
->ab_IntHandler
->h_Node
.ln_Name
= bus
->ab_Task
->tc_Node
.ln_Name
;
926 bus
->ab_IntHandler
->h_Code
= ata_Interrupt
;
927 bus
->ab_IntHandler
->h_Data
= bus
;
929 o
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
932 struct pHidd_IRQ_AddHandler __msg__
= {
933 mID
: OOP_GetMethodID(IID_Hidd_IRQ
, moHidd_IRQ_AddHandler
),
934 handlerinfo
: bus
->ab_IntHandler
,
938 if (OOP_DoMethod(o
, (OOP_Msg
)msg
))
941 OOP_DisposeObject(o
);
949 Bus task body. It doesn't really do much. It recives simply all IORequests
950 in endless lopp and calls proper handling function. The IO is Semaphore-
951 protected within a bus.
953 static void TaskCode(struct ata_Bus
*bus
, struct Task
* parent
, struct SignalSemaphore
*ssem
)
957 struct IORequest
*msg
;
959 D(bug("[ATA**] Task started (IO: 0x%x)\n", bus
->ab_Port
));
962 * don't hold parent while we analyze devices.
963 * keep things as parallel as they can be
965 ObtainSemaphoreShared(ssem
);
966 Signal(parent
, SIGBREAKF_CTRL_C
);
969 /* Get the signal used for sleeping */
970 bus
->ab_Task
= FindTask(0);
971 bus
->ab_SleepySignal
= AllocSignal(-1);
972 /* Failed to get it? Use SIGBREAKB_CTRL_E instead */
973 if (bus
->ab_SleepySignal
< 0)
974 bus
->ab_SleepySignal
= SIGBREAKB_CTRL_E
;
977 * set up irq handler now. all irqs are disabled, so prepare them one by one
979 if (!CreateInterrupt(bus
))
981 D(bug("[ATA ] Something wrong with creating interrupt?\n"));
984 sig
= 1L << bus
->ab_MsgPort
->mp_SigBit
;
986 for (iter
=0; iter
<MAX_UNIT
; ++iter
)
988 if (TRUE
== ata_setup_unit(bus
, iter
))
990 if (bus
->ab_Units
[iter
]->au_XferModes
& AF_XFER_PACKET
)
991 AddVolume(0, 0, bus
->ab_Units
[iter
]);
992 else if (bus
->ab_Units
[iter
]->au_Capacity48
!= 0)
993 AddVolume(0, bus
->ab_Units
[iter
]->au_Capacity48
, bus
->ab_Units
[iter
]);
995 AddVolume(0, bus
->ab_Units
[iter
]->au_Capacity
, bus
->ab_Units
[iter
]);
1000 * ok, we're done with init here.
1001 * tell the parent task we're ready
1003 ReleaseSemaphore(ssem
);
1005 /* Wait forever and process messages */
1010 /* Even if you get new signal, do not process it until Unit is not active */
1011 if (!(bus
->ab_Flags
& UNITF_ACTIVE
))
1013 bus
->ab_Flags
|= UNITF_ACTIVE
;
1015 /* Empty the request queue */
1016 while ((msg
= (struct IORequest
*)GetMsg(bus
->ab_MsgPort
)))
1019 HandleIO(msg
, bus
->ab_Base
);
1020 /* TD_ADDCHANGEINT doesn't require reply */
1021 if (msg
->io_Command
!= TD_ADDCHANGEINT
)
1023 ReplyMsg((struct Message
*)msg
);
1027 bus
->ab_Flags
&= ~(UNITF_INTASK
| UNITF_ACTIVE
);
1032 static void ata_Interrupt(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
1034 struct ata_Bus
*bus
= (struct ata_Bus
*)irq
->h_Data
;
1039 /* vim: set ts=4 sw=4 :*/