make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / ata.device / ata.c
blobdba4dece67031a31b56e8939c1265ac3890b8f48
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
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
28 #define DEBUG 0
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>
36 #include <oop/oop.h>
38 #include <dos/bptr.h>
40 #include <proto/exec.h>
41 #include <proto/oop.h>
43 #include "ata.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);
78 else
80 block >>= unit->au_SectorShift;
81 count >>= unit->au_SectorShift;
82 ULONG cnt = 0;
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;
88 return;
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);
117 else
119 block >>= unit->au_SectorShift;
120 count >>= unit->au_SectorShift;
121 ULONG cnt = 0;
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;
134 return;
136 io->io_Error = unit->au_Read32(unit, (ULONG)(block & 0x0fffffff), count, IOStdReq(io)->io_Data, &cnt);
138 else
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;
144 return;
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);
171 else
173 block >>= unit->au_SectorShift;
174 count >>= unit->au_SectorShift;
175 ULONG cnt = 0;
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);
202 else
204 block >>= unit->au_SectorShift;
205 count >>= unit->au_SectorShift;
206 ULONG cnt = 0;
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);
216 else
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;
230 Forbid();
232 while((msg = (struct IORequest *)GetMsg((struct MsgPort *)bus->ab_MsgPort)))
234 msg->io_Error = IOERR_ABORTED;
235 ReplyMsg((struct Message *)msg);
238 Permit();
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;
258 UBYTE sense;
260 /* Issue media check */
261 if ((sense = atapi_TestUnitOK(unit)))
264 Clear the unknown flag. We do know already, that there
265 is no media in drive
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;
278 return;
280 /* Clear the presence flag */
281 unit->au_Flags &= ~AF_DiscPresent;
283 else
286 No more mystery, we know already that there is media in
287 drive. Clear this mysterious flag.
289 unit->au_Flags &= ~AF_DiscPresenceUnknown;
291 /* Media present */
292 if (unit->au_Flags & AF_DiscPresent)
294 /* No status change. Do nothing */
295 return;
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
309 Forbid();
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);
321 Permit();
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;
338 else
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;
353 else
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;
363 else
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;
377 Forbid();
378 AddHead(&unit->au_SoftList, (struct Node *)io);
379 Permit();
381 io->io_Flags &= ~IOF_QUICK;
382 unit->au_Unit.unit_flags &= ~UNITF_ACTIVE;
385 static void cmd_RemChangeInt(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
387 Forbid();
388 Remove((struct Node *)io);
389 Permit();
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;
412 else
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;
424 dg->dg_Reserved = 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[] = {
498 CMD_RESET,
499 CMD_READ,
500 CMD_WRITE,
501 CMD_UPDATE,
502 CMD_CLEAR,
503 CMD_STOP,
504 CMD_START,
505 CMD_FLUSH,
506 TD_MOTOR,
507 TD_SEEK,
508 TD_FORMAT,
509 TD_REMOVE,
510 TD_CHANGENUM,
511 TD_CHANGESTATE,
512 TD_PROTSTATUS,
513 TD_GETNUMTRACKS,
514 TD_ADDCHANGEINT,
515 TD_REMCHANGEINT,
516 TD_GETGEOMETRY,
517 TD_EJECT,
518 TD_READ64,
519 TD_WRITE64,
520 TD_SEEK64,
521 TD_FORMAT64,
522 HD_SCSICMD,
523 TD_GETDRIVETYPE,
524 NSCMD_DEVICEQUERY,
525 NSCMD_TD_READ64,
526 NSCMD_TD_WRITE64,
527 NSCMD_TD_SEEK64,
528 NSCMD_TD_FORMAT64,
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)
538 io->io_Error = 0;
540 /* Handle few commands directly here */
541 switch (io->io_Command)
544 New Style Devices query. Introduce self as trackdisk and provide list of
545 commands supported
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);
557 break;
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
562 report error.
564 case TD_GETDRIVETYPE:
565 IOStdReq(io)->io_Actual = DRIVE_NEWSTYLE;
566 break;
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.
573 default:
574 if (io->io_Command <= (HD_SCSICMD+1))
576 if (map32[io->io_Command])
577 map32[io->io_Command](io, LIBBASE);
578 else
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);
585 else
586 cmd_Invalid(io, LIBBASE);
588 else cmd_Invalid(io, LIBBASE);
589 break;
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 */
602 if (comm <= 31)
604 if (IMMEDIATE_COMMANDS & (1 << comm))
605 slow = FALSE;
607 else if (comm == NSCMD_TD_SEEK64) slow = FALSE;
609 return slow;
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)
621 AROS_LIBFUNC_INIT
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 */
628 Disable();
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;
640 Enable();
642 /* Put the message to the bus */
643 PutMsg(unit->au_Bus->ab_MsgPort, (struct Message *)io);
645 else
647 /* Immediate command. Mark unit as active and do the command directly */
648 unit->au_Unit.unit_flags |= UNITF_ACTIVE;
649 Enable();
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"));
665 AROS_LIBFUNC_EXIT
668 AROS_LH1(LONG, AbortIO,
669 AROS_LHA(struct IORequest *, io, A1),
670 LIBBASETYPEPTR, LIBBASE, 6, ata)
672 AROS_LIBFUNC_INIT
674 /* Cannot Abort IO */
675 return 0;
677 AROS_LIBFUNC_EXIT
680 AROS_LH1(ULONG, GetRdskLba,
681 AROS_LHA(struct IORequest *, io, A1),
682 LIBBASETYPEPTR, LIBBASE, 7, ata)
684 AROS_LIBFUNC_INIT
686 return Unit(io)->au_RDBSector;
688 AROS_LIBFUNC_EXIT
691 AROS_LH1(ULONG, GetBlkSize,
692 AROS_LHA(struct IORequest *, io, A1),
693 LIBBASETYPEPTR, LIBBASE, 8, ata)
695 AROS_LIBFUNC_INIT
697 return Unit(io)->au_SectorShift;
699 AROS_LIBFUNC_EXIT
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
706 functions.
708 static void DaemonCode(LIBBASETYPEPTR LIBBASE);
710 /* Create the daemon task */
711 int ata_InitDaemonTask(LIBBASETYPEPTR LIBBASE)
713 struct Task *t;
714 struct MemList *ml;
716 struct TagItem tags[] = {
717 { TASKTAG_ARG1, (IPTR)LIBBASE },
718 { TAG_DONE, 0 }
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);
725 if (t && ml)
727 UBYTE *sp = AllocMem(STACK_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
728 t->tc_SPLower = sp;
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);
750 return (t != NULL);
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
764 int count = 0,b,d;
765 struct ata_Bus *bus;
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)
783 b = bus->ab_BusNum;
784 D(bug("[ATA++] Checking bus %d\n", b));
786 for (d=0; d < MAX_UNIT; d++)
789 * Is a device ATAPI?
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));
809 AROS_LVO_CALL3(void,
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
818 count++;
822 * INFO: we are only handling up to 64 atapi devices here
824 if (count == sizeof(ios) / sizeof(*ios))
825 break;
828 bus = (struct ata_Bus*)bus->ab_Node.mln_Succ;
831 D(bug("[ATA++] Starting sweep medium presence detection\n"));
833 if (count)
836 * Ok, open the timer.device
838 OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tr, 0);
841 * Endless loop
843 for (b=0;;++b)
846 * call separate IORequest for every ATAPI device
847 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
849 if (0 == (b & 3))
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);
879 else
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);
886 DeleteMsgPort(mp);
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)
899 struct Task *t;
900 struct MemList *ml;
902 struct TagItem tags[] = {
903 { TASKTAG_ARG1, (IPTR)bus },
904 { TASKTAG_ARG2, (IPTR)FindTask(0) },
905 { TAG_DONE, 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);
915 if (t && ml)
917 /* Setup stack and put the pointer to the bus as the only parameter */
918 UBYTE *sp = AllocMem(STACK_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
919 t->tc_SPLower = sp;
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;
949 bus->ab_Task = t;
951 /* Wake up the task */
952 NewAddTask(t, TaskCode, NULL, (struct TagItem*)&tags);
953 Wait(SIGBREAKF_CTRL_C);
956 return (t != NULL);
959 static int CreateInterrupt(struct ata_Bus *bus)
961 struct OOP_Object *o;
962 int retval = 0;
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);
976 if (o)
978 struct pHidd_IRQ_AddHandler __msg__ = {
979 mID: OOP_GetMethodID(IID_Hidd_IRQ, moHidd_IRQ_AddHandler),
980 handlerinfo: bus->ab_IntHandler,
981 id: bus->ab_Irq,
982 }, *msg = &__msg__;
984 if (OOP_DoMethod(o, (OOP_Msg)msg))
985 retval = 1;
987 OOP_DisposeObject(o);
991 return retval;
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)
1001 ULONG sig;
1002 int iter;
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]);
1027 else
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 */
1035 for (;;)
1037 Wait(sig);
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)))
1047 /* And do IO's */
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;
1067 ata_HandleIRQ(bus);
1070 /* vim: set ts=4 sw=4 :*/