Enforce libdir. On OpenSUSE the libs where stored in "lib64". They weren't
[AROS.git] / rom / devs / ata / ata.c
blob90b7ef2d7ffbfc9de507369b81440f38d8dbba4c
1 /*
2 Copyright © 2004-2014, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
9 #include <aros/debug.h>
10 #include <exec/exec.h>
11 #include <exec/resident.h>
12 #include <hidd/hidd.h>
13 #include <utility/utility.h>
14 #include <utility/tagitem.h>
15 #include <oop/oop.h>
16 #include <dos/bptr.h>
18 #include <proto/exec.h>
19 #include <proto/oop.h>
21 #include "timer.h"
22 #include "ata.h"
23 #include LC_LIBDEFS_FILE
25 #define DINIT(x)
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 static 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(struct ataBase *ATABase)
758 struct IORequest *timer; // timer
759 UBYTE b = 0;
760 ULONG sigs;
762 D(bug("[ATA**] You woke up DAEMON\n"));
765 * Prepare message ports and timer.device's request
767 timer = ata_OpenTimer(ATABase);
768 if (!timer)
770 D(bug("[ATA++] Failed to open timer!\n"));
772 Forbid();
773 Signal(ATABase->daemonParent, SIGF_SINGLE);
774 return;
777 /* Calibrate 400ns delay */
778 if (!ata_Calibrate(timer, ATABase))
780 ata_CloseTimer(timer);
781 Forbid();
782 Signal(ATABase->daemonParent, SIGF_SINGLE);
783 return;
786 /* This also signals that we have initialized successfully */
787 ATABase->ata_Daemon = FindTask(NULL);
788 Signal(ATABase->daemonParent, SIGF_SINGLE);
790 D(bug("[ATA++] Starting sweep medium presence detection\n"));
793 * Endless loop
798 * call separate IORequest for every ATAPI device
799 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
800 * FIXME: This is not a very nice approach in terms of performance.
801 * This inserts own command into command queue every 2 seconds, so
802 * this would give periodic performance drops under high loads.
803 * It would be much better if unit tasks ping their devices by themselves,
804 * when idle. This would also save us from lots of headaches with dealing
805 * with list of these requests. Additionally i start disliking all these
806 * semaphores.
808 if (0 == (b & 1))
810 struct IOStdReq *ios;
812 DB2(bug("[ATA++] Detecting media presence\n"));
813 ObtainSemaphore(&ATABase->DaemonSem);
815 ForeachNode(&ATABase->Daemon_ios, ios)
817 /* Using the request will clobber its Node. Save links. */
818 struct Node *s = ios->io_Message.mn_Node.ln_Succ;
819 struct Node *p = ios->io_Message.mn_Node.ln_Pred;
821 DoIO((struct IORequest *)ios);
823 ios->io_Message.mn_Node.ln_Succ = s;
824 ios->io_Message.mn_Node.ln_Pred = p;
827 ReleaseSemaphore(&ATABase->DaemonSem);
831 * And then hide and wait for 1 second
833 DB2(bug("[ATA++] 1 second delay, timer 0x%p...\n", timer));
834 sigs = ata_WaitTO(timer, 1, 0, SIGBREAKF_CTRL_C);
836 DB2(bug("[ATA++] Delay completed\n"));
837 b++;
838 } while (!sigs);
840 D(bug("[ATA++] Daemon quits\n"));
842 ata_CloseTimer(timer);
844 Forbid();
845 Signal(ATABase->daemonParent, SIGF_SINGLE);
849 Bus task body. It doesn't really do much. It receives simply all IORequests
850 in endless loop and calls proper handling function. The IO is Semaphore-
851 protected within a bus.
853 void BusTaskCode(struct ata_Bus *bus, struct ataBase *ATABase)
855 ULONG sig;
856 int iter;
857 struct IORequest *msg;
858 struct ata_Unit *unit;
860 DINIT(bug("[ATA**] Task started (bus: %u)\n", bus->ab_BusNum));
862 bus->ab_Timer = ata_OpenTimer(ATABase);
864 /* Get the signal used for sleeping */
865 bus->ab_Task = FindTask(0);
866 bus->ab_SleepySignal = AllocSignal(-1);
867 /* Failed to get it? Use SIGBREAKB_CTRL_E instead */
868 if (bus->ab_SleepySignal < 0)
869 bus->ab_SleepySignal = SIGBREAKB_CTRL_E;
871 sig = 1L << bus->ab_MsgPort->mp_SigBit;
873 for (iter = 0; iter < MAX_BUSUNITS; ++iter)
875 DINIT(bug("[ATA**] Device %u type %d\n", iter, bus->ab_Dev[iter]));
877 if (bus->ab_Dev[iter] > DEV_UNKNOWN)
879 unit = OOP_NewObject(ATABase->unitClass, NULL, NULL);
880 if (unit)
882 ata_init_unit(bus, unit, iter);
883 if (ata_setup_unit(bus, unit))
886 * Add unit to the bus.
887 * At this point it becomes visible to OpenDevice().
889 bus->ab_Units[iter] = unit;
891 if (unit->au_XferModes & AF_XFER_PACKET)
893 ata_RegisterVolume(0, 0, unit);
895 /* For ATAPI device we also submit media presence detection request */
896 unit->DaemonReq = (struct IOStdReq *)CreateIORequest(ATABase->DaemonPort, sizeof(struct IOStdReq));
897 if (unit->DaemonReq)
900 * We don't want to keep stalled open count of 1, so we
901 * don't call OpenDevice() here. Instead we fill in the needed
902 * fields manually.
904 unit->DaemonReq->io_Device = &ATABase->ata_Device;
905 unit->DaemonReq->io_Unit = &unit->au_Unit;
906 unit->DaemonReq->io_Command = HD_SCSICMD+1;
908 ObtainSemaphore(&ATABase->DaemonSem);
909 AddTail((struct List *)&ATABase->Daemon_ios,
910 &unit->DaemonReq->io_Message.mn_Node);
911 ReleaseSemaphore(&ATABase->DaemonSem);
914 else
916 ata_RegisterVolume(0, unit->au_Cylinders - 1, unit);
919 else
921 /* Destroy unit that couldn't be initialised */
922 OOP_DisposeObject((OOP_Object *)unit);
923 bus->ab_Dev[iter] = DEV_NONE;
929 D(bug("[ATA--] Bus %u scan finished\n", bus->ab_BusNum));
930 ReleaseSemaphore(&ATABase->DetectionSem);
932 /* Wait forever and process messages */
933 for (;;)
935 Wait(sig);
937 /* Even if you get new signal, do not process it until Unit is not active */
938 if (!(bus->ab_Flags & UNITF_ACTIVE))
940 bus->ab_Flags |= UNITF_ACTIVE;
942 /* Empty the request queue */
943 while ((msg = (struct IORequest *)GetMsg(bus->ab_MsgPort)))
945 /* And do IO's */
946 HandleIO(msg, ATABase);
947 /* TD_ADDCHANGEINT doesn't require reply */
948 if (msg->io_Command != TD_ADDCHANGEINT)
950 ReplyMsg((struct Message *)msg);
954 bus->ab_Flags &= ~(UNITF_INTASK | UNITF_ACTIVE);