added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / arch / common / ata.device / ata.c
blob5ed37d2a3374035d569a54a24cd2a778f189ecc2
1 /*
2 Copyright © 2004-2006, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
8 /*
9 * CHANGELOG:
10 * DATE NAME ENTRY
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
22 #define DEBUG 0
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>
30 #include <oop/oop.h>
32 #include <dos/bptr.h>
34 #include <proto/exec.h>
35 #include <proto/oop.h>
37 #include "ata.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);
72 else
74 block >>= unit->au_SectorShift;
75 count >>= unit->au_SectorShift;
76 ULONG cnt = 0;
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);
104 else
106 block >>= unit->au_SectorShift;
107 count >>= unit->au_SectorShift;
108 ULONG cnt = 0;
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);
118 else
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);
143 else
145 block >>= unit->au_SectorShift;
146 count >>= unit->au_SectorShift;
147 ULONG cnt = 0;
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);
174 else
176 block >>= unit->au_SectorShift;
177 count >>= unit->au_SectorShift;
178 ULONG cnt = 0;
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);
188 else
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;
202 Forbid();
204 while((msg = (struct IORequest *)GetMsg((struct MsgPort *)bus->ab_MsgPort)))
206 msg->io_Error = IOERR_ABORTED;
207 ReplyMsg((struct Message *)msg);
210 Permit();
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;
230 UBYTE sense;
232 /* Issue media check */
233 if ((sense = atapi_TestUnitOK(unit)))
236 Clear the unknown flag. We do know already, that there
237 is no media in drive
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;
250 return;
252 /* Clear the presence flag */
253 unit->au_Flags &= ~AF_DiscPresent;
255 else
258 No more mystery, we know already that there is media in
259 drive. Clear this mysterious flag.
261 unit->au_Flags &= ~AF_DiscPresenceUnknown;
263 /* Media present */
264 if (unit->au_Flags & AF_DiscPresent)
266 /* No status change. Do nothing */
267 return;
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
281 Forbid();
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);
293 Permit();
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;
310 else
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;
325 else
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;
335 else
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;
349 Forbid();
350 AddHead(&unit->au_SoftList, (struct Node *)io);
351 Permit();
353 io->io_Flags &= ~IOF_QUICK;
354 unit->au_Unit.unit_flags &= ~UNITF_ACTIVE;
357 static void cmd_RemChangeInt(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
359 Forbid();
360 Remove((struct Node *)io);
361 Permit();
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;
384 else
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;
396 dg->dg_Reserved = 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[] = {
470 CMD_RESET,
471 CMD_READ,
472 CMD_WRITE,
473 CMD_UPDATE,
474 CMD_CLEAR,
475 CMD_STOP,
476 CMD_START,
477 CMD_FLUSH,
478 TD_MOTOR,
479 TD_SEEK,
480 TD_FORMAT,
481 TD_REMOVE,
482 TD_CHANGENUM,
483 TD_CHANGESTATE,
484 TD_PROTSTATUS,
485 TD_GETNUMTRACKS,
486 TD_ADDCHANGEINT,
487 TD_REMCHANGEINT,
488 TD_GETGEOMETRY,
489 TD_EJECT,
490 TD_READ64,
491 TD_WRITE64,
492 TD_SEEK64,
493 TD_FORMAT64,
494 HD_SCSICMD,
495 TD_GETDRIVETYPE,
496 NSCMD_DEVICEQUERY,
497 NSCMD_TD_READ64,
498 NSCMD_TD_WRITE64,
499 NSCMD_TD_SEEK64,
500 NSCMD_TD_FORMAT64,
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)
510 io->io_Error = 0;
512 /* Handle few commands directly here */
513 switch (io->io_Command)
516 New Style Devices query. Introduce self as trackdisk and provide list of
517 commands supported
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);
529 break;
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
534 report error.
536 case TD_GETDRIVETYPE:
537 IOStdReq(io)->io_Actual = DRIVE_NEWSTYLE;
538 break;
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.
545 default:
546 if (io->io_Command <= (HD_SCSICMD+1))
548 if (map32[io->io_Command])
549 map32[io->io_Command](io, LIBBASE);
550 else
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);
557 else
558 cmd_Invalid(io, LIBBASE);
560 else cmd_Invalid(io, LIBBASE);
561 break;
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 */
574 if (comm <= 31)
576 if (IMMEDIATE_COMMANDS & (1 << comm))
577 slow = FALSE;
579 else if (comm == NSCMD_TD_SEEK64) slow = FALSE;
581 return slow;
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)
593 AROS_LIBFUNC_INIT
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 */
600 Disable();
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;
612 Enable();
614 /* Put the message to the bus */
615 PutMsg(unit->au_Bus->ab_MsgPort, (struct Message *)io);
617 else
619 /* Immediate command. Mark unit as active and do the command directly */
620 unit->au_Unit.unit_flags |= UNITF_ACTIVE;
621 Enable();
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"));
637 AROS_LIBFUNC_EXIT
640 AROS_LH1(LONG, AbortIO,
641 AROS_LHA(struct IORequest *, io, A1),
642 LIBBASETYPEPTR, LIBBASE, 6, ata)
644 AROS_LIBFUNC_INIT
646 /* Cannot Abort IO */
647 return 0;
649 AROS_LIBFUNC_EXIT
652 AROS_LH1(ULONG, GetRdskLba,
653 AROS_LHA(struct IORequest *, io, A1),
654 LIBBASETYPEPTR, LIBBASE, 7, ata)
656 AROS_LIBFUNC_INIT
658 return Unit(io)->au_RDBSector;
660 AROS_LIBFUNC_EXIT
663 AROS_LH1(ULONG, GetBlkSize,
664 AROS_LHA(struct IORequest *, io, A1),
665 LIBBASETYPEPTR, LIBBASE, 8, ata)
667 AROS_LIBFUNC_INIT
669 return Unit(io)->au_SectorShift;
671 AROS_LIBFUNC_EXIT
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
678 functions.
680 static void DaemonCode(LIBBASETYPEPTR LIBBASE);
682 /* Create the daemon task */
683 int ata_InitDaemonTask(LIBBASETYPEPTR LIBBASE)
685 struct Task *t;
686 struct MemList *ml;
688 struct TagItem tags[] = {
689 { TASKTAG_ARG1, (IPTR)LIBBASE },
690 { TAG_DONE, 0 }
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);
697 if (t && ml)
699 UBYTE *sp = AllocMem(STACK_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
700 t->tc_SPLower = sp;
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);
722 return (t != NULL);
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
736 int count = 0,b,d;
737 struct ata_Bus *bus;
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)
755 b = bus->ab_BusNum;
756 D(bug("[ATA++] Checking bus %d\n", b));
758 for (d=0; d < MAX_UNIT; d++)
761 * Is a device ATAPI?
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));
781 AROS_LVO_CALL3(void,
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
790 count++;
794 * INFO: we are only handling up to 64 atapi devices here
796 if (count == sizeof(ios) / sizeof(*ios))
797 break;
800 bus = (struct ata_Bus*)bus->ab_Node.mln_Succ;
803 D(bug("[ATA++] Starting sweep medium presence detection\n"));
805 if (count)
808 * Ok, open the timer.device
810 OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tr, 0);
813 * Endless loop
815 for (;;)
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);
834 else
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);
841 DeleteMsgPort(mp);
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)
855 struct Task *t;
856 struct MemList *ml;
858 struct TagItem tags[] = {
859 { TASKTAG_ARG1, (IPTR)bus },
860 { TAG_DONE, 0 }
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);
870 if (t && ml)
872 /* Setup stack and put the pointer to the bus as the only parameter */
873 UBYTE *sp = AllocMem(STACK_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
874 t->tc_SPLower = sp;
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;
904 bus->ab_Task = t;
906 /* Wake up the task */
907 NewAddTask(t, TaskCode, NULL, (struct TagItem*)&tags);
910 return (t != NULL);
913 static int CreateInterrupt(struct ata_Bus *bus)
915 struct OOP_Object *o;
916 int retval = 0;
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);
937 if (o)
939 struct pHidd_IRQ_AddHandler __msg__ = {
940 mID: OOP_GetMethodID(IID_Hidd_IRQ, moHidd_IRQ_AddHandler),
941 handlerinfo: bus->ab_IntHandler,
942 id: bus->ab_Irq,
943 }, *msg = &__msg__;
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))
952 retval = 1;
958 OOP_DisposeObject(o);
962 return retval;
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)
972 ULONG sig;
973 int iter;
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]);
1008 else
1009 AddVolume(0, bus->ab_Units[iter]->au_Capacity, bus->ab_Units[iter]);
1014 /* Wait forever and process messages */
1015 for (;;)
1017 Wait(sig);
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)))
1027 /* And do IO's */
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;
1047 bus->ab_IntCnt++;
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)
1058 bus->ab_Timeout--;
1060 if (!bus->ab_Timeout)
1062 D(bug("[ATA ] ERROR: Command timeout expired\n"));
1063 Signal(bus->ab_Task, SIGBREAKF_CTRL_C);