revert between 56095 -> 55830 in arch
[AROS.git] / rom / devs / ata / ata.c
blob05c3ce6572156fe21e862cd5bcba4fc9569123f2
1 /*
2 Copyright © 2004-2019, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
9 #include <aros/debug.h>
11 #include <proto/exec.h>
13 /* We want all other bases obtained from our base */
14 #define __NOLIBBASE__
16 #include <proto/oop.h>
18 #include <exec/exec.h>
19 #include <exec/resident.h>
20 #include <hidd/hidd.h>
21 #include <utility/utility.h>
22 #include <utility/tagitem.h>
23 #include <oop/oop.h>
24 #include <dos/bptr.h>
26 #include <devices/ata.h>
28 #include "timer.h"
29 #include "ata.h"
30 #include LC_LIBDEFS_FILE
32 #define DINIT(x)
34 //---------------------------IO Commands---------------------------------------
36 /* Invalid comand does nothing, complains only. */
37 static void cmd_Invalid(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
39 D(bug("[ATA%02ld] %s(%d)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, io->io_Command));
40 io->io_Error = IOERR_NOCMD;
43 /* Don't need to reset the drive? */
44 static void cmd_Reset(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
46 IOStdReq(io)->io_Actual = 0;
49 /* CMD_READ implementation */
50 static void cmd_Read32(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
52 struct ata_Unit *unit = (struct ata_Unit *)IOStdReq(io)->io_Unit;
54 if (AF_Removable == (unit->au_Flags & (AF_Removable | AF_DiscPresent)))
56 D(bug("[ATA%02ld] %s: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit->au_UnitNum, __func__));
57 io->io_Error = TDERR_DiskChanged;
58 return;
61 ULONG block = IOStdReq(io)->io_Offset;
62 ULONG count = IOStdReq(io)->io_Length;
64 D(bug("[ATA%02ld] %s(%08x, %08x)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, block, count));
66 ULONG mask = (1 << unit->au_SectorShift) - 1;
69 During this IO call it should be sure that both offset and
70 length are already aligned properly to sector boundaries.
72 if ((block & mask) | (count & mask))
74 D(bug("[ATA%02ld] %s: offset or length not sector-aligned.\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
75 cmd_Invalid(io, LIBBASE);
77 else
79 block >>= unit->au_SectorShift;
80 count >>= unit->au_SectorShift;
81 ULONG cnt = 0;
83 if ((0 == (unit->au_XferModes & AF_XFER_PACKET)) && ((block + count) > unit->au_Capacity))
85 bug("[ATA%02ld] %s: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, block, count, unit->au_Capacity);
86 io->io_Error = IOERR_BADADDRESS;
87 return;
90 /* Call the Unit's access funtion */
91 io->io_Error = unit->au_Read32(unit, block, count,
92 IOStdReq(io)->io_Data, &cnt);
94 IOStdReq(io)->io_Actual = cnt;
99 NSCMD_TD_READ64, TD_READ64 implementation. Basically the same, just packs
100 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
102 static void cmd_Read64(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
104 struct ata_Unit *unit = (struct ata_Unit *)IOStdReq(io)->io_Unit;
106 if (AF_Removable == (unit->au_Flags & (AF_Removable | AF_DiscPresent)))
108 D(bug("[ATA%02ld] %s: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit->au_UnitNum, __func__));
109 io->io_Error = TDERR_DiskChanged;
110 return;
113 UQUAD block = IOStdReq(io)->io_Offset | (UQUAD)(IOStdReq(io)->io_Actual) << 32;
114 ULONG count = IOStdReq(io)->io_Length;
116 D(bug("[ATA%02ld] %s(%08x-%08x, %08x)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, IOStdReq(io)->io_Actual, IOStdReq(io)->io_Offset, count));
118 ULONG mask = (1 << unit->au_SectorShift) - 1;
120 if ((block & (UQUAD)mask) | (count & mask) | (count == 0))
122 D(bug("[ATA%02ld] %s: offset or length not sector-aligned.\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
123 cmd_Invalid(io, LIBBASE);
125 else
127 block >>= unit->au_SectorShift;
128 count >>= unit->au_SectorShift;
129 ULONG cnt = 0;
132 If the sum of sector offset and the sector count doesn't overflow
133 the 28-bit LBA address, use 32-bit access for speed and simplicity.
134 Otherwise do the 48-bit LBA addressing.
136 if ((block + count) < 0x0fffffff)
138 if ((0 == (unit->au_XferModes & AF_XFER_PACKET)) && ((block + count) > unit->au_Capacity))
140 bug("[ATA%02ld] %s: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, block, count, unit->au_Capacity);
141 io->io_Error = IOERR_BADADDRESS;
142 return;
144 io->io_Error = unit->au_Read32(unit, (ULONG)(block & 0x0fffffff), count, IOStdReq(io)->io_Data, &cnt);
146 else
148 if ((0 == (unit->au_XferModes & AF_XFER_PACKET)) && ((block + count) > unit->au_Capacity48))
150 bug("[ATA%02ld] %s: Requested block (%lx:%08lx;%ld) outside disk range (%lx:%08lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, block>>32, block&0xfffffffful, count, unit->au_Capacity48>>32, unit->au_Capacity48 & 0xfffffffful);
151 io->io_Error = IOERR_BADADDRESS;
152 return;
155 io->io_Error = unit->au_Read64(unit, block, count, IOStdReq(io)->io_Data, &cnt);
158 IOStdReq(io)->io_Actual = cnt;
162 /* CMD_WRITE implementation */
163 static void cmd_Write32(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
165 struct ata_Unit *unit = (struct ata_Unit *)IOStdReq(io)->io_Unit;
167 if (AF_Removable == (unit->au_Flags & (AF_Removable | AF_DiscPresent)))
169 D(bug("[ATA%02ld] %s: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit->au_UnitNum, __func__));
170 io->io_Error = TDERR_DiskChanged;
171 return;
174 ULONG block = IOStdReq(io)->io_Offset;
175 ULONG count = IOStdReq(io)->io_Length;
177 D(bug("[ATA%02ld] %s(%08x, %08x)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, block, count));
179 ULONG mask = (1 << unit->au_SectorShift) - 1;
182 During this IO call it should be sure that both offset and
183 length are already aligned properly to sector boundaries.
185 if ((block & mask) | (count & mask))
187 D(bug("[ATA%02ld] %s: offset or length not sector-aligned.\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
188 cmd_Invalid(io, LIBBASE);
190 else
192 block >>= unit->au_SectorShift;
193 count >>= unit->au_SectorShift;
194 ULONG cnt = 0;
196 if ((0 == (unit->au_XferModes & AF_XFER_PACKET))
197 && ((block + count) > unit->au_Capacity))
199 bug("[ATA%02ld] %s: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum,
200 __func__,
201 block, count, unit->au_Capacity);
202 io->io_Error = IOERR_BADADDRESS;
203 return;
206 /* Call the Unit's access funtion */
207 io->io_Error = unit->au_Write32(unit, block, count,
208 IOStdReq(io)->io_Data, &cnt);
210 IOStdReq(io)->io_Actual = cnt;
215 NSCMD_TD_WRITE64, TD_WRITE64 implementation. Basically the same, just packs
216 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
218 static void cmd_Write64(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
220 struct ata_Unit *unit = (struct ata_Unit *)IOStdReq(io)->io_Unit;
222 if (AF_Removable == (unit->au_Flags & (AF_Removable | AF_DiscPresent)))
224 D(bug("[ATA%02ld] %s: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit->au_UnitNum, __func__));
225 io->io_Error = TDERR_DiskChanged;
226 return;
229 UQUAD block = IOStdReq(io)->io_Offset | (UQUAD)(IOStdReq(io)->io_Actual) << 32;
230 ULONG count = IOStdReq(io)->io_Length;
232 D(bug("[ATA%02ld] %s(%08x-%08x, %08x)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, IOStdReq(io)->io_Actual, IOStdReq(io)->io_Offset, count));
234 ULONG mask = (1 << unit->au_SectorShift) - 1;
236 if ((block & mask) | (count & mask) | (count==0))
238 D(bug("[ATA%02ld] %s: offset or length not sector-aligned.\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
239 cmd_Invalid(io, LIBBASE);
241 else
243 block >>= unit->au_SectorShift;
244 count >>= unit->au_SectorShift;
245 ULONG cnt = 0;
248 If the sum of sector offset and the sector count doesn't overflow
249 the 28-bit LBA address, use 32-bit access for speed and simplicity.
250 Otherwise do the 48-bit LBA addressing.
252 if ((block + count) < 0x0fffffff)
254 if ((0 == (unit->au_XferModes & AF_XFER_PACKET))
255 && ((block + count) > unit->au_Capacity))
257 bug("[ATA%02ld] %s: Requested block (%lx;%ld) outside disk range "
258 "(%lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, block, count, unit->au_Capacity);
259 io->io_Error = IOERR_BADADDRESS;
260 return;
262 io->io_Error = unit->au_Write32(unit, (ULONG)(block & 0x0fffffff),
263 count, IOStdReq(io)->io_Data, &cnt);
265 else
267 if ((0 == (unit->au_XferModes & AF_XFER_PACKET))
268 && ((block + count) > unit->au_Capacity48))
270 bug("[ATA%02ld] %s: Requested block (%lx:%08lx;%ld) outside disk "
271 "range (%lx:%08lx)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum,
272 __func__,
273 block>>32, block&0xfffffffful,
274 count, unit->au_Capacity48>>32,
275 unit->au_Capacity48 & 0xfffffffful);
276 io->io_Error = IOERR_BADADDRESS;
277 return;
280 io->io_Error = unit->au_Write64(unit, block, count,
281 IOStdReq(io)->io_Data, &cnt);
283 IOStdReq(io)->io_Actual = cnt;
288 /* use CMD_FLUSH to force all IO waiting commands to abort */
289 static void cmd_Flush(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
291 struct IORequest *msg;
292 struct ata_Bus *bus = ((struct ata_Unit *)io->io_Unit)->au_Bus;
294 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
296 Forbid();
298 while((msg = (struct IORequest *)GetMsg((struct MsgPort *)bus->ab_MsgPort)))
300 msg->io_Error = IOERR_ABORTED;
301 ReplyMsg((struct Message *)msg);
304 Permit();
308 Internal command used to check whether the media in drive has been changed
309 since last call. If so, the handlers given by user are called.
311 static void cmd_TestChanged(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
313 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
314 struct IORequest *msg;
316 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
318 if ((unit->au_XferModes & AF_XFER_PACKET) && (unit->au_Flags & AF_Removable))
320 atapi_TestUnitOK(unit);
321 if (unit->au_Flags & AF_DiscChanged)
323 unit->au_ChangeNum++;
325 Forbid();
327 /* old-fashioned RemoveInt call first */
328 if (unit->au_RemoveInt)
329 Cause(unit->au_RemoveInt);
331 /* And now the whole list of possible calls */
332 ForeachNode(&unit->au_SoftList, msg)
334 Cause((struct Interrupt *)IOStdReq(msg)->io_Data);
337 unit->au_Flags &= ~AF_DiscChanged;
339 Permit();
344 static void cmd_Update(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
346 /* Do nothing now. In near future there should be drive cache flush though */
347 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
350 static void cmd_Remove(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
352 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
354 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
356 if (unit->au_RemoveInt)
357 io->io_Error = TDERR_DriveInUse;
358 else
359 unit->au_RemoveInt = IOStdReq(io)->io_Data;
362 static void cmd_ChangeNum(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
364 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
366 IOStdReq(io)->io_Actual = ((struct ata_Unit *)io->io_Unit)->au_ChangeNum;
369 static void cmd_ChangeState(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
371 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
373 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
375 if (unit->au_Flags & AF_DiscPresent)
376 IOStdReq(io)->io_Actual = 0;
377 else
378 IOStdReq(io)->io_Actual = 1;
380 D(bug("[ATA%02ld] %s: Media %s\n", unit->au_UnitNum, __func__, IOStdReq(io)->io_Actual ? "ABSENT" : "PRESENT"));
383 static void cmd_ProtStatus(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
385 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
387 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
389 if (unit->au_DevType)
390 IOStdReq(io)->io_Actual = -1;
391 else
392 IOStdReq(io)->io_Actual = 0;
396 static void cmd_GetNumTracks(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
398 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
400 IOStdReq(io)->io_Actual = ((struct ata_Unit *)io->io_Unit)->au_Cylinders;
403 static void cmd_AddChangeInt(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
405 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
407 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
409 Forbid();
410 AddHead(&unit->au_SoftList, (struct Node *)io);
411 Permit();
413 io->io_Flags &= ~IOF_QUICK;
414 unit->au_Unit.unit_flags &= ~UNITF_ACTIVE;
417 static void cmd_RemChangeInt(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
419 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
421 Forbid();
422 Remove((struct Node *)io);
423 Permit();
426 static void cmd_Eject(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
428 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
430 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
432 IOStdReq(io)->io_Error = unit->au_Eject(unit);
433 cmd_TestChanged(io, LIBBASE);
436 static void cmd_GetGeometry(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
438 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
440 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
442 if (IOStdReq(io)->io_Length == sizeof(struct DriveGeometry))
444 struct DriveGeometry *dg = (struct DriveGeometry *)IOStdReq(io)->io_Data;
446 dg->dg_SectorSize = 1 << unit->au_SectorShift;
448 if (unit->au_Capacity48 != 0)
450 if ((unit->au_Capacity48 >> 32) != 0)
451 dg->dg_TotalSectors = 0xffffffff;
452 else
453 dg->dg_TotalSectors = unit->au_Capacity48;
455 else
456 dg->dg_TotalSectors = unit->au_Capacity;
458 dg->dg_Cylinders = unit->au_Cylinders;
459 dg->dg_CylSectors = unit->au_Sectors * unit->au_Heads;
460 dg->dg_Heads = unit->au_Heads;
461 dg->dg_TrackSectors = unit->au_Sectors;
462 dg->dg_BufMemType = MEMF_PUBLIC;
463 dg->dg_DeviceType = unit->au_DevType;
464 if (dg->dg_DeviceType != DG_DIRECT_ACCESS)
465 dg->dg_Flags = (unit->au_Flags & AF_Removable) ? DGF_REMOVABLE : 0;
466 else
467 dg->dg_Flags = 0;
468 dg->dg_Reserved = 0;
470 IOStdReq(io)->io_Actual = sizeof(struct DriveGeometry);
472 else if (IOStdReq(io)->io_Length == 514)
474 CopyMemQuick(unit->au_Drive, IOStdReq(io)->io_Data, 512);
476 else io->io_Error = TDERR_NotSpecified;
479 static void cmd_DirectScsi(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
481 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
483 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
485 IOStdReq(io)->io_Actual = sizeof(struct SCSICmd);
486 if (unit->au_XferModes & AF_XFER_PACKET)
488 io->io_Error = unit->au_DirectSCSI(unit, (struct SCSICmd *)IOStdReq(io)->io_Data);
490 else if (unit->au_DevType == DG_DIRECT_ACCESS)
492 io->io_Error = SCSIEmu(unit, (struct SCSICmd *)IOStdReq(io)->io_Data);
494 else io->io_Error = IOERR_BADADDRESS;
497 static BOOL ValidSMARTCmd(struct IORequest *io)
499 #if (0)
500 if ((IOStdReq(io)->io_Reserved1) != (IOStdReq(io)->io_Reserved2))
501 return FALSE;
503 switch (IOStdReq(io)->io_Reserved1)
505 case SMARTC_TEST_AVAIL:
506 case SMARTC_READ_VALUES:
507 case SMARTC_READ_THRESHOLDS:
508 if (!IOStdReq(io)->io_Data)
510 D(bug("[ATA%02ld] %s: invalid io_Data (%p)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, IOStdReq(io)->io_Data));
511 io->io_Error = IOERR_BADADDRESS;
512 return FALSE;
514 if ((IOStdReq(io)->io_Offset != SMARTC_TEST_AVAIL) && (IOStdReq(io)->io_Length != SMART_DATA_LENGTH))
516 D(bug("[ATA%02ld] %s: invalid io_Length (%d)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, IOStdReq(io)->io_Length));
517 io->io_Error = IOERR_BADLENGTH;
518 return FALSE;
520 break;
522 case SMARTC_ENABLE:
523 case SMARTC_DISABLE:
524 case SMARTC_STATUS:
525 break;
527 default:
528 D(bug("[ATA%02ld] %s: invalid SMART command (%d)\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, IOStdReq(io)->io_Offset));
529 io->io_Error = IOERR_NOCMD;
530 return FALSE;
532 #endif
533 return TRUE;
536 static void cmd_SMART(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
538 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
539 #if (0)
540 struct ata_Bus *bus = unit->au_Bus;
541 UBYTE u;
542 #endif
543 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
545 if (unit->au_Flags & AF_DiscPresent)
547 io->io_Error = IOERR_OPENFAIL;
548 return;
551 if (!ValidSMARTCmd(io))
552 return;
553 #if (0)
554 u = unit->au_UnitNum & 1;
556 if (bus->ab_Dev[u] == DEV_ATA || bus->ab_Dev[u] == DEV_SATA)
558 if (IOStdReq(io)->io_Reserved1 == ATAFEATURE_TEST_AVAIL)
560 if (IOStdReq(io)->io_Length >= sizeof(ULONG))
562 *((ULONG *)IOStdReq(io)->io_Data) = SMART_MAGIC_ID;
563 IOStdReq(io)->io_Actual = sizeof(ULONG);
565 io->io_Error = 0;
566 return;
568 ata_SMARTCmd(IOStdReq(io));
570 else
571 #endif
572 io->io_Error = IOERR_NOCMD;
575 static void cmd_TRIM(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
577 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
579 D(bug("[ATA%02ld] %s()\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
581 if ((unit->au_Drive->id_ATAVersion >= 7) && (unit->au_Drive->id_DSManagement & 1))
583 D(bug("[ATA%02ld] %s: Unit supports TRIM\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
584 #if (0)
585 if (IOStdReq(io)->io_Reserved1 == ATAFEATURE_TEST_AVAIL)
587 if (IOStdReq(io)->io_Length >= sizeof(ULONG))
589 *((ULONG *)IOStdReq(io)->io_Data) = TRIM_MAGIC_ID;
590 IOStdReq(io)->io_Actual = sizeof(ULONG);
592 io->io_Error = 0;
593 return;
595 ata_TRIMCmd(IOStdReq(io));
596 #endif
598 else
599 io->io_Error = IOERR_NOCMD;
602 //-----------------------------------------------------------------------------
605 command translation tables - used to call proper IO functions.
608 #define N_TD_READ64 0
609 #define N_TD_WRITE64 1
610 #define N_TD_SEEK64 2
611 #define N_TD_FORMAT64 3
613 typedef void (*mapfunc)(struct IORequest *, LIBBASETYPEPTR);
615 static mapfunc const map64[]= {
616 [N_TD_READ64] = cmd_Read64,
617 [N_TD_WRITE64] = cmd_Write64,
618 [N_TD_SEEK64] = cmd_Reset,
619 [N_TD_FORMAT64] = cmd_Write64
622 static mapfunc const map32[] = {
623 [CMD_INVALID] = cmd_Invalid,
624 [CMD_RESET] = cmd_Reset,
625 [CMD_READ] = cmd_Read32,
626 [CMD_WRITE] = cmd_Write32,
627 [CMD_UPDATE] = cmd_Update,
628 [CMD_CLEAR] = cmd_Reset,
629 [CMD_STOP] = cmd_Reset,
630 [CMD_START] = cmd_Reset,
631 [CMD_FLUSH] = cmd_Flush,
632 [TD_MOTOR] = cmd_Reset,
633 [TD_SEEK] = cmd_Reset,
634 [TD_FORMAT] = cmd_Write32,
635 [TD_REMOVE] = cmd_Remove,
636 [TD_CHANGENUM] = cmd_ChangeNum,
637 [TD_CHANGESTATE]= cmd_ChangeState,
638 [TD_PROTSTATUS] = cmd_ProtStatus,
639 [TD_RAWREAD] = cmd_Invalid,
640 [TD_RAWWRITE] = cmd_Invalid,
641 [TD_GETNUMTRACKS] = cmd_GetNumTracks,
642 [TD_ADDCHANGEINT] = cmd_AddChangeInt,
643 [TD_REMCHANGEINT] = cmd_RemChangeInt,
644 [TD_GETGEOMETRY]= cmd_GetGeometry,
645 [TD_EJECT] = cmd_Eject,
646 [TD_READ64] = cmd_Read64,
647 [TD_WRITE64] = cmd_Write64,
648 [TD_SEEK64] = cmd_Reset,
649 [TD_FORMAT64] = cmd_Write64,
650 [HD_SCSICMD] = cmd_DirectScsi,
651 [HD_SCSICMD+1] = cmd_TestChanged,
652 [HD_SMARTCMD] = cmd_SMART,
653 [HD_TRIMCMD] = cmd_TRIM
656 static UWORD const NSDSupported[] = {
657 CMD_RESET,
658 CMD_READ,
659 CMD_WRITE,
660 CMD_UPDATE,
661 CMD_CLEAR,
662 CMD_STOP,
663 CMD_START,
664 CMD_FLUSH,
665 TD_MOTOR,
666 TD_SEEK,
667 TD_FORMAT,
668 TD_REMOVE,
669 TD_CHANGENUM,
670 TD_CHANGESTATE,
671 TD_PROTSTATUS,
672 TD_GETNUMTRACKS,
673 TD_ADDCHANGEINT,
674 TD_REMCHANGEINT,
675 TD_GETGEOMETRY,
676 TD_EJECT,
677 TD_READ64,
678 TD_WRITE64,
679 TD_SEEK64,
680 TD_FORMAT64,
681 HD_SCSICMD,
682 TD_GETDRIVETYPE,
683 NSCMD_DEVICEQUERY,
684 NSCMD_TD_READ64,
685 NSCMD_TD_WRITE64,
686 NSCMD_TD_SEEK64,
687 NSCMD_TD_FORMAT64,
688 HD_SMARTCMD,
689 HD_TRIMCMD,
694 Do proper IO actions depending on the request. It's called from the bus
695 tasks and from BeginIO in case of immediate commands.
697 static void HandleIO(struct IORequest *io, LIBBASETYPEPTR LIBBASE)
699 io->io_Error = 0;
701 /* Handle few commands directly here */
702 switch (io->io_Command)
705 New Style Devices query. Introduce self as trackdisk and provide list of
706 commands supported
708 case NSCMD_DEVICEQUERY:
710 struct NSDeviceQueryResult *nsdq = (struct NSDeviceQueryResult *)IOStdReq(io)->io_Data;
711 nsdq->DevQueryFormat = 0;
712 nsdq->SizeAvailable = sizeof(struct NSDeviceQueryResult);
713 nsdq->DeviceType = NSDEVTYPE_TRACKDISK;
714 nsdq->DeviceSubType = 0;
715 nsdq->SupportedCommands = (UWORD *)NSDSupported;
717 IOStdReq(io)->io_Actual = sizeof(struct NSDeviceQueryResult);
718 break;
721 New Style Devices report here the 'NSTY' - only if such value is
722 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
723 report error.
725 case TD_GETDRIVETYPE:
726 IOStdReq(io)->io_Actual = DRIVE_NEWSTYLE;
727 break;
730 Call all other commands using the command pointer tables for 32- and
731 64-bit accesses. If requested function is defined call it, otherwise
732 make the function cmd_Invalid.
734 default:
735 if ((io->io_Command <= (HD_SCSICMD+1)) || (io->io_Command >= HD_SMARTCMD && io->io_Command <= HD_TRIMCMD))
737 if (map32[io->io_Command])
738 map32[io->io_Command](io, LIBBASE);
739 else
740 cmd_Invalid(io, LIBBASE);
742 else if (io->io_Command >= NSCMD_TD_READ64 && io->io_Command <= NSCMD_TD_FORMAT64)
744 if (map64[io->io_Command - NSCMD_TD_READ64])
745 map64[io->io_Command - NSCMD_TD_READ64](io, LIBBASE);
746 else
747 cmd_Invalid(io, LIBBASE);
749 else cmd_Invalid(io, LIBBASE);
750 break;
755 static const ULONG IMMEDIATE_COMMANDS = 0x803ff1e3; // 10000000001111111111000111100011
757 /* See whether the command can be done quick */
758 static BOOL isSlow(struct IORequest *io)
760 BOOL slow = TRUE; /* Assume always slow command */
762 /* For commands with numbers <= 31 check the mask */
763 if (io->io_Command <= 31)
765 if (IMMEDIATE_COMMANDS & (1 << io->io_Command))
766 slow = FALSE;
768 #if(0)
769 else if ((io->io_Command >= HD_SMARTCMD && io->io_Command <= HD_TRIMCMD) &&
770 (IOStdReq(io)->io_Reserved1 == ATAFEATURE_TEST_AVAIL)) slow = FALSE;
771 #endif
772 else if (io->io_Command == NSCMD_TD_SEEK64 || io->io_Command == NSCMD_DEVICEQUERY) slow = FALSE;
774 return slow;
778 Try to do IO commands. All commands which require talking with ata devices
779 will be handled slow, that is they will be passed to bus task which will
780 execute them as soon as hardware will be free.
782 AROS_LH1(void, BeginIO,
783 AROS_LHA(struct IORequest *, io, A1),
784 LIBBASETYPEPTR, LIBBASE, 5, ata)
786 AROS_LIBFUNC_INIT
788 struct ata_Unit *unit = (struct ata_Unit *)io->io_Unit;
790 io->io_Message.mn_Node.ln_Type = NT_MESSAGE;
792 /* Disable interrupts for a while to modify message flags */
793 Disable();
795 D(bug("[ATA%02ld] %s: Executing IO Command %lx\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__, io->io_Command));
798 If the command is not-immediate, or presence of disc is still unknown,
799 let the bus task do the job.
801 if (isSlow(io))
803 unit->au_Unit.unit_flags |= UNITF_ACTIVE | UNITF_INTASK;
804 io->io_Flags &= ~IOF_QUICK;
805 Enable();
807 /* Put the message to the bus */
808 PutMsg(unit->au_Bus->ab_MsgPort, (struct Message *)io);
810 else
812 D(bug("[ATA%02ld] %s: ->Fast command\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
814 /* Immediate command. Mark unit as active and do the command directly */
815 unit->au_Unit.unit_flags |= UNITF_ACTIVE;
816 Enable();
817 HandleIO(io, LIBBASE);
819 unit->au_Unit.unit_flags &= ~UNITF_ACTIVE;
822 If the command was not intended to be immediate and it was not the
823 TD_ADDCHANGEINT, reply to confirm command execution now.
825 if (!(io->io_Flags & IOF_QUICK) && (io->io_Command != TD_ADDCHANGEINT))
827 ReplyMsg((struct Message *)io);
831 D(bug("[ATA%02ld] %s: Done\n", ((struct ata_Unit*)io->io_Unit)->au_UnitNum, __func__));
832 AROS_LIBFUNC_EXIT
835 AROS_LH1(LONG, AbortIO,
836 AROS_LHA(struct IORequest *, io, A1),
837 LIBBASETYPEPTR, LIBBASE, 6, ata)
839 AROS_LIBFUNC_INIT
841 /* Cannot Abort IO */
842 return 0;
844 AROS_LIBFUNC_EXIT
847 AROS_LH1(ULONG, GetRdskLba,
848 AROS_LHA(struct IORequest *, io, A1),
849 LIBBASETYPEPTR, LIBBASE, 7, ata)
851 AROS_LIBFUNC_INIT
853 return 0;
855 AROS_LIBFUNC_EXIT
858 AROS_LH1(ULONG, GetBlkSize,
859 AROS_LHA(struct IORequest *, io, A1),
860 LIBBASETYPEPTR, LIBBASE, 8, ata)
862 AROS_LIBFUNC_INIT
864 return Unit(io)->au_SectorShift;
866 AROS_LIBFUNC_EXIT
870 * The daemon of ata.device first opens all ATAPI devices and then enters
871 * endless loop. Every 2 seconds it tells ATAPI units to check the media
872 * presence. In case of any state change they will rise user-specified
873 * functions.
874 * The check is done by sending HD_SCSICMD+1 command (internal testchanged
875 * command). ATAPI units should already handle the command further.
877 void DaemonCode(struct ataBase *ATABase)
879 struct IORequest *timer; // timer
880 UBYTE b = 0;
881 ULONG sigs;
883 D(bug("[ATA**] You woke up DAEMON\n"));
886 * Prepare message ports and timer.device's request
888 timer = ata_OpenTimer(ATABase);
889 if (!timer)
891 D(bug("[ATA++] Failed to open timer!\n"));
893 Forbid();
894 Signal(ATABase->daemonParent, SIGF_SINGLE);
895 return;
898 /* Calibrate 400ns delay */
899 if (!ata_Calibrate(timer, ATABase))
901 ata_CloseTimer(timer);
902 Forbid();
903 Signal(ATABase->daemonParent, SIGF_SINGLE);
904 return;
907 /* This also signals that we have initialized successfully */
908 ATABase->ata_Daemon = FindTask(NULL);
909 Signal(ATABase->daemonParent, SIGF_SINGLE);
911 D(bug("[ATA++] Starting sweep medium presence detection\n"));
914 * Endless loop
919 * call separate IORequest for every ATAPI device
920 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
921 * FIXME: This is not a very nice approach in terms of performance.
922 * This inserts own command into command queue every 2 seconds, so
923 * this would give periodic performance drops under high loads.
924 * It would be much better if unit tasks ping their devices by themselves,
925 * when idle. This would also save us from lots of headaches with dealing
926 * with list of these requests. Additionally i start disliking all these
927 * semaphores.
929 if (0 == (b & 1))
931 struct IOStdReq *ios;
933 DB2(bug("[ATA++] Detecting media presence\n"));
934 ObtainSemaphore(&ATABase->DaemonSem);
936 ForeachNode(&ATABase->Daemon_ios, ios)
938 /* Using the request will clobber its Node. Save links. */
939 struct Node *s = ios->io_Message.mn_Node.ln_Succ;
940 struct Node *p = ios->io_Message.mn_Node.ln_Pred;
942 DoIO((struct IORequest *)ios);
944 ios->io_Message.mn_Node.ln_Succ = s;
945 ios->io_Message.mn_Node.ln_Pred = p;
948 ReleaseSemaphore(&ATABase->DaemonSem);
952 * And then hide and wait for 1 second
954 DB2(bug("[ATA++] 1 second delay, timer 0x%p...\n", timer));
955 sigs = ata_WaitTO(timer, 1, 0, SIGBREAKF_CTRL_C);
957 DB2(bug("[ATA++] Delay completed\n"));
958 b++;
959 } while (!sigs);
961 D(bug("[ATA++] Daemon quits\n"));
963 ata_CloseTimer(timer);
965 Forbid();
966 Signal(ATABase->daemonParent, SIGF_SINGLE);
970 Bus task body. It doesn't really do much. It receives simply all IORequests
971 in endless loop and calls proper handling function. The IO is Semaphore-
972 protected within a bus.
974 void BusTaskCode(struct ata_Bus *bus, struct ataBase *ATABase)
976 ULONG sig;
977 int iter;
978 struct IORequest *msg;
979 OOP_Object *unitObj;
980 struct ata_Unit *unit;
982 DINIT(bug("[ATA**] Task started (bus: %u)\n", bus->ab_BusNum));
984 bus->ab_Timer = ata_OpenTimer(ATABase);
985 bus->ab_BounceBufferPool = CreatePool(MEMF_CLEAR | MEMF_31BIT, 131072, 65536);
987 /* Get the signal used for sleeping */
988 bus->ab_Task = FindTask(0);
989 bus->ab_SleepySignal = AllocSignal(-1);
990 /* Failed to get it? Use SIGBREAKB_CTRL_E instead */
991 if (bus->ab_SleepySignal < 0)
992 bus->ab_SleepySignal = SIGBREAKB_CTRL_E;
994 sig = 1L << bus->ab_MsgPort->mp_SigBit;
996 for (iter = 0; iter < MAX_BUSUNITS; ++iter)
998 DINIT(bug("[ATA**] Device %u type %d\n", iter, bus->ab_Dev[iter]));
1000 if (bus->ab_Dev[iter] > DEV_UNKNOWN)
1002 unitObj = OOP_NewObject(ATABase->unitClass, NULL, NULL);
1003 if (unitObj)
1005 unit = OOP_INST_DATA(ATABase->unitClass, unitObj);
1006 ata_init_unit(bus, unit, iter);
1007 if (ata_setup_unit(bus, unit))
1010 * Add unit to the bus.
1011 * At this point it becomes visible to OpenDevice().
1013 bus->ab_Units[iter] = unitObj;
1015 if (unit->au_XferModes & AF_XFER_PACKET)
1017 ata_RegisterVolume(0, 0, unit);
1019 /* For ATAPI device we also submit media presence detection request */
1020 unit->DaemonReq = (struct IOStdReq *)CreateIORequest(ATABase->DaemonPort, sizeof(struct IOStdReq));
1021 if (unit->DaemonReq)
1024 * We don't want to keep stalled open count of 1, so we
1025 * don't call OpenDevice() here. Instead we fill in the needed
1026 * fields manually.
1028 unit->DaemonReq->io_Device = &ATABase->ata_Device;
1029 unit->DaemonReq->io_Unit = &unit->au_Unit;
1030 unit->DaemonReq->io_Command = HD_SCSICMD+1;
1032 ObtainSemaphore(&ATABase->DaemonSem);
1033 AddTail((struct List *)&ATABase->Daemon_ios,
1034 &unit->DaemonReq->io_Message.mn_Node);
1035 ReleaseSemaphore(&ATABase->DaemonSem);
1038 else
1040 ata_RegisterVolume(0, unit->au_Cylinders - 1, unit);
1043 else
1045 /* Destroy unit that couldn't be initialised */
1046 OOP_DisposeObject((OOP_Object *)unit);
1047 bus->ab_Dev[iter] = DEV_NONE;
1053 D(bug("[ATA--] Bus %u scan finished\n", bus->ab_BusNum));
1054 ReleaseSemaphore(&ATABase->DetectionSem);
1056 /* Wait forever and process messages */
1057 for (;;)
1059 Wait(sig);
1061 /* Even if you get new signal, do not process it until Unit is not active */
1062 if (!(bus->ab_Flags & UNITF_ACTIVE))
1064 bus->ab_Flags |= UNITF_ACTIVE;
1066 /* Empty the request queue */
1067 while ((msg = (struct IORequest *)GetMsg(bus->ab_MsgPort)))
1069 /* And do IO's */
1070 HandleIO(msg, ATABase);
1071 /* TD_ADDCHANGEINT doesn't require reply */
1072 if (msg->io_Command != TD_ADDCHANGEINT)
1074 ReplyMsg((struct Message *)msg);
1078 bus->ab_Flags &= ~(UNITF_INTASK | UNITF_ACTIVE);