Added 'Resident' field to ensure that the handler is included in the
[AROS.git] / rom / devs / ata / ata.c
blob47b9d4ecb06ce4c5710b8420ea05223025ad7080
1 /*
2 Copyright © 2004-2009, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
9 #include <aros/debug.h>
11 #include <exec/types.h>
12 #include <exec/exec.h>
13 #include <exec/resident.h>
14 #include <utility/utility.h>
15 #include <utility/tagitem.h>
16 #include <oop/oop.h>
17 #include "timer.h"
19 #include <dos/bptr.h>
21 #include <proto/exec.h>
22 #include <proto/oop.h>
24 #include "ata.h"
25 #include LC_LIBDEFS_FILE
27 //---------------------------IO Commands---------------------------------------
29 /* Invalid comand does nothing, complains only. */
30 static void cmd_Invalid(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
32 D(bug("[ATA%02ld] cmd_Invalid: %d\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, io->io_Command));
33 io->io_Error = IOERR_NOCMD;
36 /* Don't need to reset the drive? */
37 static void cmd_Reset(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
39 IOStdReq(io)->io_Actual = 0;
42 /* CMD_READ implementation */
43 static void cmd_Read32(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
45 struct ata_Unit *unit = (struct ata_Unit *)IOStdReq(io)->io_Unit;
47 if (AF_Removable == (unit->au_Flags & (AF_Removable | AF_DiscPresent)))
49 D(bug("[ATA%02ld] cmd_Read32: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit->au_UnitNum));
50 io->io_Error = TDERR_DiskChanged;
51 return;
54 ULONG block = IOStdReq(io)->io_Offset;
55 ULONG count = IOStdReq(io)->io_Length;
57 D(bug("[ATA%02ld] cmd_Read32(%08x, %08x)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, block, count));
59 ULONG mask = (1 << unit->au_SectorShift) - 1;
62 During this IO call it should be sure that both offset and
63 length are already aligned properly to sector boundaries.
65 if ((block & mask) | (count & mask))
67 D(bug("[ATA%02ld] cmd_Read32: offset or length not sector-aligned.\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
68 cmd_Invalid(io, LIBBASE);
70 else
72 block >>= unit->au_SectorShift;
73 count >>= unit->au_SectorShift;
74 ULONG cnt = 0;
76 if ((0 == (unit->au_XferModes & AF_XFER_PACKET)) && ((block + count) > unit->au_Capacity))
78 bug("[ATA%02ld] cmd_Read32: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, block, count, unit->au_Capacity);
79 io->io_Error = IOERR_BADADDRESS;
80 return;
83 /* Call the Unit's access funtion */
84 io->io_Error = unit->au_Read32(unit, block, count,
85 IOStdReq(io)->io_Data, &cnt);
87 IOStdReq(io)->io_Actual = cnt;
92 NSCMD_TD_READ64, TD_READ64 implementation. Basically the same, just packs
93 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
95 static void cmd_Read64(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
97 struct ata_Unit *unit = (struct ata_Unit *)IOStdReq(io)->io_Unit;
99 if (AF_Removable == (unit->au_Flags & (AF_Removable | AF_DiscPresent)))
101 D(bug("[ATA%02ld] cmd_Read64: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit->au_UnitNum));
102 io->io_Error = TDERR_DiskChanged;
103 return;
106 UQUAD block = IOStdReq(io)->io_Offset | (UQUAD)(IOStdReq(io)->io_Actual) << 32;
107 ULONG count = IOStdReq(io)->io_Length;
109 D(bug("[ATA%02ld] cmd_Read64(%08x-%08x, %08x)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, IOStdReq(io)->io_Actual, IOStdReq(io)->io_Offset, count));
111 ULONG mask = (1 << unit->au_SectorShift) - 1;
113 if ((block & (UQUAD)mask) | (count & mask) | (count == 0))
115 D(bug("[ATA%02ld] cmd_Read64: offset or length not sector-aligned.\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
116 cmd_Invalid(io, LIBBASE);
118 else
120 block >>= unit->au_SectorShift;
121 count >>= unit->au_SectorShift;
122 ULONG cnt = 0;
125 If the sum of sector offset and the sector count doesn't overflow
126 the 28-bit LBA address, use 32-bit access for speed and simplicity.
127 Otherwise do the 48-bit LBA addressing.
129 if ((block + count) < 0x0fffffff)
131 if ((0 == (unit->au_XferModes & AF_XFER_PACKET)) && ((block + count) > unit->au_Capacity))
133 bug("[ATA%02ld] cmd_Read64: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, block, count, unit->au_Capacity);
134 io->io_Error = IOERR_BADADDRESS;
135 return;
137 io->io_Error = unit->au_Read32(unit, (ULONG)(block & 0x0fffffff), count, IOStdReq(io)->io_Data, &cnt);
139 else
141 if ((0 == (unit->au_XferModes & AF_XFER_PACKET)) && ((block + count) > unit->au_Capacity48))
143 bug("[ATA%02ld] cmd_Read64: Requested block (%lx:%08lx;%ld) outside disk range (%lx:%08lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, block>>32, block&0xfffffffful, count, unit->au_Capacity48>>32, unit->au_Capacity48 & 0xfffffffful);
144 io->io_Error = IOERR_BADADDRESS;
145 return;
148 io->io_Error = unit->au_Read64(unit, block, count, IOStdReq(io)->io_Data, &cnt);
151 IOStdReq(io)->io_Actual = cnt;
155 /* CMD_WRITE implementation */
156 static void cmd_Write32(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
158 struct ata_Unit *unit = (struct ata_Unit *)IOStdReq(io)->io_Unit;
160 if (AF_Removable == (unit->au_Flags & (AF_Removable | AF_DiscPresent)))
162 D(bug("[ATA%02ld] cmd_Write32: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit->au_UnitNum));
163 io->io_Error = TDERR_DiskChanged;
164 return;
167 ULONG block = IOStdReq(io)->io_Offset;
168 ULONG count = IOStdReq(io)->io_Length;
170 D(bug("[ATA%02ld] cmd_Write32(%08x, %08x)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, block, count));
172 ULONG mask = (1 << unit->au_SectorShift) - 1;
175 During this IO call it should be sure that both offset and
176 length are already aligned properly to sector boundaries.
178 if ((block & mask) | (count & mask))
180 D(bug("[ATA%02ld] cmd_Write32: offset or length not sector-aligned.\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
181 cmd_Invalid(io, LIBBASE);
183 else
185 block >>= unit->au_SectorShift;
186 count >>= unit->au_SectorShift;
187 ULONG cnt = 0;
189 if ((0 == (unit->au_XferModes & AF_XFER_PACKET))
190 && ((block + count) > unit->au_Capacity))
192 bug("[ATA%02ld] cmd_Write32: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum,
193 block, count, unit->au_Capacity);
194 io->io_Error = IOERR_BADADDRESS;
195 return;
198 /* Call the Unit's access funtion */
199 io->io_Error = unit->au_Write32(unit, block, count,
200 IOStdReq(io)->io_Data, &cnt);
202 IOStdReq(io)->io_Actual = cnt;
207 NSCMD_TD_WRITE64, TD_WRITE64 implementation. Basically the same, just packs
208 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
210 static void cmd_Write64(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
212 struct ata_Unit *unit = (struct ata_Unit *)IOStdReq(io)->io_Unit;
214 if (AF_Removable == (unit->au_Flags & (AF_Removable | AF_DiscPresent)))
216 D(bug("[ATA%02ld] cmd_Write64: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit->au_UnitNum));
217 io->io_Error = TDERR_DiskChanged;
218 return;
222 UQUAD block = IOStdReq(io)->io_Offset | (UQUAD)(IOStdReq(io)->io_Actual) << 32;
223 ULONG count = IOStdReq(io)->io_Length;
225 D(bug("[ATA%02ld] cmd_Write64(%08x-%08x, %08x)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, IOStdReq(io)->io_Actual, IOStdReq(io)->io_Offset, count));
227 ULONG mask = (1 << unit->au_SectorShift) - 1;
229 if ((block & mask) | (count & mask) | (count==0))
231 D(bug("[ATA%02ld] cmd_Write64: offset or length not sector-aligned.\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
232 cmd_Invalid(io, LIBBASE);
234 else
236 block >>= unit->au_SectorShift;
237 count >>= unit->au_SectorShift;
238 ULONG cnt = 0;
241 If the sum of sector offset and the sector count doesn't overflow
242 the 28-bit LBA address, use 32-bit access for speed and simplicity.
243 Otherwise do the 48-bit LBA addressing.
245 if ((block + count) < 0x0fffffff)
247 if ((0 == (unit->au_XferModes & AF_XFER_PACKET))
248 && ((block + count) > unit->au_Capacity))
250 bug("[ATA%02ld] cmd_Write64: Requested block (%lx;%ld) outside disk range "
251 "(%lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, block, count, unit->au_Capacity);
252 io->io_Error = IOERR_BADADDRESS;
253 return;
255 io->io_Error = unit->au_Write32(unit, (ULONG)(block & 0x0fffffff),
256 count, IOStdReq(io)->io_Data, &cnt);
258 else
260 if ((0 == (unit->au_XferModes & AF_XFER_PACKET))
261 && ((block + count) > unit->au_Capacity48))
263 bug("[ATA%02ld] cmd_Write64: Requested block (%lx:%08lx;%ld) outside disk "
264 "range (%lx:%08lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum,
265 block>>32, block&0xfffffffful,
266 count, unit->au_Capacity48>>32,
267 unit->au_Capacity48 & 0xfffffffful);
268 io->io_Error = IOERR_BADADDRESS;
269 return;
272 io->io_Error = unit->au_Write64(unit, block, count,
273 IOStdReq(io)->io_Data, &cnt);
275 IOStdReq(io)->io_Actual = cnt;
280 /* use CMD_FLUSH to force all IO waiting commands to abort */
281 static void cmd_Flush(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
283 struct IORequest *msg;
284 struct ata_Bus *bus = ((struct ata_Unit *)io->io_Unit)->au_Bus;
286 D(bug("[ATA%02ld] cmd_Flush()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
288 Forbid();
290 while((msg = (struct IORequest *)GetMsg((struct MsgPort *)bus->ab_MsgPort)))
292 msg->io_Error = IOERR_ABORTED;
293 ReplyMsg((struct Message *)msg);
296 Permit();
300 Internal command used to check whether the media in drive has been changed
301 since last call. If so, the handlers given by user are called.
303 static void cmd_TestChanged(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
305 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
306 struct IORequest *msg;
308 D(bug("[ATA%02ld] cmd_TestChanged()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
310 if ((unit->au_XferModes & AF_XFER_PACKET) && (unit->au_Flags & AF_Removable))
312 atapi_TestUnitOK(unit);
313 if (unit->au_Flags & AF_DiscChanged)
315 unit->au_ChangeNum++;
317 Forbid();
319 /* old-fashioned RemoveInt call first */
320 if (unit->au_RemoveInt)
321 Cause(unit->au_RemoveInt);
323 /* And now the whole list of possible calls */
324 ForeachNode(&unit->au_SoftList, msg)
326 Cause((struct Interrupt *)IOStdReq(msg)->io_Data);
329 unit->au_Flags &= ~AF_DiscChanged;
331 Permit();
336 static void cmd_Update(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
338 /* Do nothing now. In near future there should be drive cache flush though */
339 D(bug("[ATA%02ld] cmd_Update()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
342 static void cmd_Remove(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
344 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
346 D(bug("[ATA%02ld] cmd_Remove()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
348 if (unit->au_RemoveInt)
349 io->io_Error = TDERR_DriveInUse;
350 else
351 unit->au_RemoveInt = IOStdReq(io)->io_Data;
354 static void cmd_ChangeNum(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
356 D(bug("[ATA%02ld] cmd_ChangeNum()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
358 IOStdReq(io)->io_Actual = ((struct ata_Unit *)io->io_Unit)->au_ChangeNum;
361 static void cmd_ChangeState(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
363 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
365 D(bug("[ATA%02ld] cmd_ChangeState()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
367 if (unit->au_Flags & AF_DiscPresent)
368 IOStdReq(io)->io_Actual = 0;
369 else
370 IOStdReq(io)->io_Actual = 1;
372 D(bug("[ATA%02ld] cmd_ChangeState: Media %s\n", unit->au_UnitNum, IOStdReq(io)->io_Actual ? "ABSENT" : "PRESENT"));
375 static void cmd_ProtStatus(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
377 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
379 D(bug("[ATA%02ld] cmd_ProtStatus()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
381 if (unit->au_DevType)
382 IOStdReq(io)->io_Actual = -1;
383 else
384 IOStdReq(io)->io_Actual = 0;
388 static void cmd_GetNumTracks(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
390 D(bug("[ATA%02ld] cmd_GetNumTracks()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
392 IOStdReq(io)->io_Actual = ((struct ata_Unit *)io->io_Unit)->au_Cylinders;
395 static void cmd_AddChangeInt(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
397 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
399 D(bug("[ATA%02ld] cmd_AddChangeInt()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
401 Forbid();
402 AddHead(&unit->au_SoftList, (struct Node *)io);
403 Permit();
405 io->io_Flags &= ~IOF_QUICK;
406 unit->au_Unit.unit_flags &= ~UNITF_ACTIVE;
409 static void cmd_RemChangeInt(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
411 D(bug("[ATA%02ld] cmd_RemChangeInt()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
413 Forbid();
414 Remove((struct Node *)io);
415 Permit();
418 static void cmd_Eject(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
420 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
422 D(bug("[ATA%02ld] cmd_Eject()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
424 IOStdReq(io)->io_Error = unit->au_Eject(unit);
425 cmd_TestChanged(io, LIBBASE);
428 static void cmd_GetGeometry(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
430 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
432 D(bug("[ATA%02ld] cmd_GetGeometry()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
434 if (IOStdReq(io)->io_Length == sizeof(struct DriveGeometry))
436 struct DriveGeometry *dg = (struct DriveGeometry *)IOStdReq(io)->io_Data;
438 dg->dg_SectorSize = 1 << unit->au_SectorShift;
440 if (unit->au_Capacity48 != 0)
442 if ((unit->au_Capacity48 >> 32) != 0)
443 dg->dg_TotalSectors = 0xffffffff;
444 else
445 dg->dg_TotalSectors = unit->au_Capacity48;
447 else
448 dg->dg_TotalSectors = unit->au_Capacity;
450 dg->dg_Cylinders = unit->au_Cylinders;
451 dg->dg_CylSectors = unit->au_Sectors * unit->au_Heads;
452 dg->dg_Heads = unit->au_Heads;
453 dg->dg_TrackSectors = unit->au_Sectors;
454 dg->dg_BufMemType = MEMF_PUBLIC;
455 dg->dg_DeviceType = unit->au_DevType;
456 if (dg->dg_DeviceType != DG_DIRECT_ACCESS)
457 dg->dg_Flags = (unit->au_Flags & AF_Removable) ? DGF_REMOVABLE : 0;
458 else
459 dg->dg_Flags = 0;
460 dg->dg_Reserved = 0;
462 IOStdReq(io)->io_Actual = sizeof(struct DriveGeometry);
464 else if (IOStdReq(io)->io_Length == 514)
466 CopyMemQuick(unit->au_Drive, IOStdReq(io)->io_Data, 512);
468 else io->io_Error = TDERR_NotSpecified;
471 static void cmd_DirectScsi(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
473 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
475 D(bug("[ATA%02ld] cmd_DirectScsi()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
477 IOStdReq(io)->io_Actual = sizeof(struct SCSICmd);
478 if (unit->au_XferModes & AF_XFER_PACKET)
480 io->io_Error = unit->au_DirectSCSI(unit, (struct SCSICmd *)IOStdReq(io)->io_Data);
482 else if (unit->au_DevType == DG_DIRECT_ACCESS)
484 io->io_Error = SCSIEmu(unit, (struct SCSICmd *)IOStdReq(io)->io_Data);
486 else io->io_Error = IOERR_BADADDRESS;
489 //-----------------------------------------------------------------------------
492 command translation tables - used to call proper IO functions.
495 #define N_TD_READ64 0
496 #define N_TD_WRITE64 1
497 #define N_TD_SEEK64 2
498 #define N_TD_FORMAT64 3
500 typedef void (*mapfunc)(struct IORequest *, LIBBASETYPEPTR);
502 static mapfunc const map64[]= {
503 [N_TD_READ64] = cmd_Read64,
504 [N_TD_WRITE64] = cmd_Write64,
505 [N_TD_SEEK64] = cmd_Reset,
506 [N_TD_FORMAT64] = cmd_Write64
509 static mapfunc const map32[] = {
510 [CMD_INVALID] = cmd_Invalid,
511 [CMD_RESET] = cmd_Reset,
512 [CMD_READ] = cmd_Read32,
513 [CMD_WRITE] = cmd_Write32,
514 [CMD_UPDATE] = cmd_Update,
515 [CMD_CLEAR] = cmd_Reset,
516 [CMD_STOP] = cmd_Reset,
517 [CMD_START] = cmd_Reset,
518 [CMD_FLUSH] = cmd_Flush,
519 [TD_MOTOR] = cmd_Reset,
520 [TD_SEEK] = cmd_Reset,
521 [TD_FORMAT] = cmd_Write32,
522 [TD_REMOVE] = cmd_Remove,
523 [TD_CHANGENUM] = cmd_ChangeNum,
524 [TD_CHANGESTATE]= cmd_ChangeState,
525 [TD_PROTSTATUS] = cmd_ProtStatus,
526 [TD_RAWREAD] = cmd_Invalid,
527 [TD_RAWWRITE] = cmd_Invalid,
528 [TD_GETNUMTRACKS] = cmd_GetNumTracks,
529 [TD_ADDCHANGEINT] = cmd_AddChangeInt,
530 [TD_REMCHANGEINT] = cmd_RemChangeInt,
531 [TD_GETGEOMETRY]= cmd_GetGeometry,
532 [TD_EJECT] = cmd_Eject,
533 [TD_READ64] = cmd_Read64,
534 [TD_WRITE64] = cmd_Write64,
535 [TD_SEEK64] = cmd_Reset,
536 [TD_FORMAT64] = cmd_Write64,
537 [HD_SCSICMD] = cmd_DirectScsi,
538 [HD_SCSICMD+1] = cmd_TestChanged,
541 static UWORD const NSDSupported[] = {
542 CMD_RESET,
543 CMD_READ,
544 CMD_WRITE,
545 CMD_UPDATE,
546 CMD_CLEAR,
547 CMD_STOP,
548 CMD_START,
549 CMD_FLUSH,
550 TD_MOTOR,
551 TD_SEEK,
552 TD_FORMAT,
553 TD_REMOVE,
554 TD_CHANGENUM,
555 TD_CHANGESTATE,
556 TD_PROTSTATUS,
557 TD_GETNUMTRACKS,
558 TD_ADDCHANGEINT,
559 TD_REMCHANGEINT,
560 TD_GETGEOMETRY,
561 TD_EJECT,
562 TD_READ64,
563 TD_WRITE64,
564 TD_SEEK64,
565 TD_FORMAT64,
566 HD_SCSICMD,
567 TD_GETDRIVETYPE,
568 NSCMD_DEVICEQUERY,
569 NSCMD_TD_READ64,
570 NSCMD_TD_WRITE64,
571 NSCMD_TD_SEEK64,
572 NSCMD_TD_FORMAT64,
577 Do proper IO actions depending on the request. It's called from the bus
578 tasks and from BeginIO in case of immediate commands.
580 static void HandleIO(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
582 io->io_Error = 0;
584 /* Handle few commands directly here */
585 switch (io->io_Command)
588 New Style Devices query. Introduce self as trackdisk and provide list of
589 commands supported
591 case NSCMD_DEVICEQUERY:
593 struct NSDeviceQueryResult *nsdq = (struct NSDeviceQueryResult *)IOStdReq(io)->io_Data;
594 nsdq->DevQueryFormat = 0;
595 nsdq->SizeAvailable = sizeof(struct NSDeviceQueryResult);
596 nsdq->DeviceType = NSDEVTYPE_TRACKDISK;
597 nsdq->DeviceSubType = 0;
598 nsdq->SupportedCommands = (UWORD *)NSDSupported;
600 IOStdReq(io)->io_Actual = sizeof(struct NSDeviceQueryResult);
601 break;
604 New Style Devices report here the 'NSTY' - only if such value is
605 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
606 report error.
608 case TD_GETDRIVETYPE:
609 IOStdReq(io)->io_Actual = DRIVE_NEWSTYLE;
610 break;
613 Call all other commands using the command pointer tables for 32- and
614 64-bit accesses. If requested function is defined call it, otherwise
615 make the function cmd_Invalid.
617 default:
618 if (io->io_Command <= (HD_SCSICMD+1))
620 if (map32[io->io_Command])
621 map32[io->io_Command](io, LIBBASE);
622 else
623 cmd_Invalid(io, LIBBASE);
625 else if (io->io_Command >= NSCMD_TD_READ64 && io->io_Command <= NSCMD_TD_FORMAT64)
627 if (map64[io->io_Command - NSCMD_TD_READ64])
628 map64[io->io_Command - NSCMD_TD_READ64](io, LIBBASE);
629 else
630 cmd_Invalid(io, LIBBASE);
632 else cmd_Invalid(io, LIBBASE);
633 break;
638 static const ULONG IMMEDIATE_COMMANDS = 0x803ff1e3; // 10000000001111111111000111100011
640 /* See whether the command can be done quick */
641 BOOL isSlow(ULONG comm)
643 BOOL slow = TRUE; /* Assume always slow command */
645 /* For commands with numbers <= 31 check the mask */
646 if (comm <= 31)
648 if (IMMEDIATE_COMMANDS & (1 << comm))
649 slow = FALSE;
651 else if (comm == NSCMD_TD_SEEK64) slow = FALSE;
653 return slow;
657 Try to do IO commands. All commands which require talking with ata devices
658 will be handled slow, that is they will be passed to bus task which will
659 execute them as soon as hardware will be free.
661 AROS_LH1(void, BeginIO,
662 AROS_LHA(struct IORequest *, io, A1),
663 LIBBASETYPEPTR, LIBBASE, 5, ata)
665 AROS_LIBFUNC_INIT
667 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
669 io->io_Message.mn_Node.ln_Type = NT_MESSAGE;
671 /* Disable interrupts for a while to modify message flags */
672 Disable();
674 D(bug("[ATA%02ld] BeginIO: Executing IO Command %lx\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, io->io_Command));
677 If the command is not-immediate, or presence of disc is still unknown,
678 let the bus task do the job.
680 if (isSlow(io->io_Command))
682 unit->au_Unit.unit_flags |= UNITF_ACTIVE | UNITF_INTASK;
683 io->io_Flags &= ~IOF_QUICK;
684 Enable();
686 /* Put the message to the bus */
687 PutMsg(unit->au_Bus->ab_MsgPort, (struct Message *)io);
689 else
691 D(bug("[ATA%02ld] Fast command\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
693 /* Immediate command. Mark unit as active and do the command directly */
694 unit->au_Unit.unit_flags |= UNITF_ACTIVE;
695 Enable();
696 HandleIO(io, LIBBASE);
698 unit->au_Unit.unit_flags &= ~UNITF_ACTIVE;
701 If the command was not intended to be immediate and it was not the
702 TD_ADDCHANGEINT, reply to confirm command execution now.
704 if (!(io->io_Flags & IOF_QUICK) && (io->io_Command != TD_ADDCHANGEINT))
706 ReplyMsg((struct Message *)io);
710 D(bug("[ATA%02ld] BeginIO: Done\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum));
711 AROS_LIBFUNC_EXIT
714 AROS_LH1(LONG, AbortIO,
715 AROS_LHA(struct IORequest *, io, A1),
716 LIBBASETYPEPTR, LIBBASE, 6, ata)
718 AROS_LIBFUNC_INIT
720 /* Cannot Abort IO */
721 return 0;
723 AROS_LIBFUNC_EXIT
726 AROS_LH1(ULONG, GetRdskLba,
727 AROS_LHA(struct IORequest *, io, A1),
728 LIBBASETYPEPTR, LIBBASE, 7, ata)
730 AROS_LIBFUNC_INIT
732 return 0;
734 AROS_LIBFUNC_EXIT
737 AROS_LH1(ULONG, GetBlkSize,
738 AROS_LHA(struct IORequest *, io, A1),
739 LIBBASETYPEPTR, LIBBASE, 8, ata)
741 AROS_LIBFUNC_INIT
743 return Unit(io)->au_SectorShift;
745 AROS_LIBFUNC_EXIT
749 * The daemon of ata.device first opens all ATAPI devices and then enters
750 * endless loop. Every 2 seconds it tells ATAPI units to check the media
751 * presence. In case of any state change they will rise user-specified
752 * functions.
753 * The check is done by sending HD_SCSICMD+1 command (internal testchanged
754 * command). ATAPI units should already handle the command further.
756 void DaemonCode(LIBBASETYPEPTR LIBBASE)
758 struct MsgPort *myport; // Message port used with ata.device
759 struct IORequest *timer; // timer
760 struct IOStdReq *ios[64]; // Placeholder for unit messages
761 int count = 0,b,d;
762 struct ata_Bus *bus;
764 D(bug("[ATA**] You woke up DAEMON\n"));
767 * Prepare message ports and timer.device's request
769 myport = CreateMsgPort();
770 timer = ata_OpenTimer(LIBBASE);
771 bus = (struct ata_Bus*)LIBBASE->ata_Buses.mlh_Head;
774 * grab all buses, see if there is an atapi cdrom connected or anything alike
775 * TODO: good thing to consider putting extra code here for future hotplug support *if any*
777 while (bus->ab_Node.mln_Succ != NULL)
779 b = bus->ab_BusNum;
780 D(bug("[ATA++] Checking bus %d\n", b));
782 for (d=0; d < MAX_BUSUNITS; d++)
785 * Is a device ATAPI?
787 D(bug("[ATA++] Unit %d is of type %x\n", (b<<1)+d, bus->ab_Dev[d]));
789 if (bus->ab_Dev[d] >= DEV_ATAPI)
792 * Atapi device found. Create IOStdReq for it
794 ios[count] = (struct IOStdReq *) CreateIORequest(myport, sizeof(struct IOStdReq));
796 ios[count]->io_Command = HD_SCSICMD + 1;
799 * And force OpenDevice call. Don't use direct call as it's unsafe
800 * and not nice at all.
802 * so THIS is an OpenDevice().....
804 D(bug("[ATA++] Opening ATAPI device, unit %d\n", (b<<1)|d));
805 AROS_LVO_CALL3NR(void,
806 AROS_LCA(struct IORequest *, (struct IORequest *)(ios[count]), A1),
807 AROS_LCA(ULONG, (b << 1) | d, D0),
808 AROS_LCA(ULONG, 0, D1),
809 LIBBASETYPEPTR, LIBBASE, 1, ata);
812 * increase amount of ATAPI devices in system
814 count++;
818 * INFO: we are only handling up to 64 atapi devices here
820 if (count == sizeof(ios) / sizeof(*ios))
821 break;
823 bus = (struct ata_Bus*)bus->ab_Node.mln_Succ;
826 D(bug("[ATA++] Starting sweep medium presence detection\n"));
829 * Endless loop
831 for (b=0;;++b)
834 * call separate IORequest for every ATAPI device
835 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
837 if (0 == (b & 1))
839 D(bug("[ATA++] Detecting media presence\n"));
840 for (d=0; d < count; d++)
841 DoIO((struct IORequest *)ios[d]);
845 * check / trigger all buses waiting for an irq
847 DB2(bug("[ATA++] Checking timeouts...\n"));
848 Forbid();
849 ForeachNode(&LIBBASE->ata_Buses, bus)
851 if (bus->ab_Timeout >= 0)
853 if (0 > (--bus->ab_Timeout))
855 Signal(bus->ab_Task, SIGBREAKF_CTRL_C);
859 Permit();
862 * And then hide and wait for 1 second
864 DB2(bug("[ATA++] 1 second delay, timer 0x%p...\n", timer));
865 ata_WaitTO(timer, 1, 0, 0);
867 DB2(bug("[ATA++] Delay completed\n"));
872 Bus task body. It doesn't really do much. It receives simply all IORequests
873 in endless loop and calls proper handling function. The IO is Semaphore-
874 protected within a bus.
876 void BusTaskCode(struct ata_Bus *bus, struct Task* parent, struct SignalSemaphore *ssem)
878 ULONG sig;
879 int iter;
880 struct IORequest *msg;
881 struct ata_Unit *unit;
883 D(bug("[ATA**] Task started (IO: 0x%x)\n", bus->ab_Port));
886 * don't hold parent while we analyze devices.
887 * keep things as parallel as they can be
889 ObtainSemaphoreShared(ssem);
890 Signal(parent, SIGBREAKF_CTRL_C);
892 bus->ab_Timer = ata_OpenTimer(bus->ab_Base);
894 /* Get the signal used for sleeping */
895 bus->ab_Task = FindTask(0);
896 bus->ab_SleepySignal = AllocSignal(-1);
897 /* Failed to get it? Use SIGBREAKB_CTRL_E instead */
898 if (bus->ab_SleepySignal < 0)
899 bus->ab_SleepySignal = SIGBREAKB_CTRL_E;
902 * set up irq handler now. all irqs are disabled, so prepare them one by one
904 if (!bus->ab_Driver->CreateInterrupt(bus))
906 D(bug("[ATA ] Something wrong with creating interrupt?\n"));
909 sig = 1L << bus->ab_MsgPort->mp_SigBit;
911 for (iter=0; iter<MAX_BUSUNITS; ++iter)
913 unit = bus->ab_Units[iter];
914 if (ata_setup_unit(bus, iter))
916 if (unit->au_XferModes & AF_XFER_PACKET)
917 ata_RegisterVolume(0, 0, unit);
918 else
919 ata_RegisterVolume(0, unit->au_Cylinders - 1, unit);
921 else
923 /* Destroy unit that couldn't be initialised */
924 FreeVecPooled(bus->ab_Base->ata_MemPool, unit);
925 bus->ab_Units[iter] = NULL;
926 bus->ab_Dev[iter] = DEV_NONE;
931 * ok, we're done with init here.
932 * tell the parent task we're ready
934 ReleaseSemaphore(ssem);
936 /* Wait forever and process messages */
937 for (;;)
939 Wait(sig);
941 /* Even if you get new signal, do not process it until Unit is not active */
942 if (!(bus->ab_Flags & UNITF_ACTIVE))
944 bus->ab_Flags |= UNITF_ACTIVE;
946 /* Empty the request queue */
947 while ((msg = (struct IORequest *)GetMsg(bus->ab_MsgPort)))
949 /* And do IO's */
950 HandleIO(msg, bus->ab_Base);
951 /* TD_ADDCHANGEINT doesn't require reply */
952 if (msg->io_Command != TD_ADDCHANGEINT)
954 ReplyMsg((struct Message *)msg);
958 bus->ab_Flags &= ~(UNITF_INTASK | UNITF_ACTIVE);
963 /* vim: set ts=4 sw=4 :*/