2 Copyright © 2004-2019, The AROS Development Team. All rights reserved
9 #include <aros/debug.h>
11 #include <proto/exec.h>
13 /* We want all other bases obtained from our base */
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>
26 #include <devices/ata.h>
30 #include LC_LIBDEFS_FILE
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
;
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
);
79 block
>>= unit
->au_SectorShift
;
80 count
>>= unit
->au_SectorShift
;
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
;
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
;
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
);
127 block
>>= unit
->au_SectorShift
;
128 count
>>= unit
->au_SectorShift
;
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
;
144 io
->io_Error
= unit
->au_Read32(unit
, (ULONG
)(block
& 0x0fffffff), count
, IOStdReq(io
)->io_Data
, &cnt
);
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
;
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
;
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
);
192 block
>>= unit
->au_SectorShift
;
193 count
>>= unit
->au_SectorShift
;
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
,
201 block
, count
, unit
->au_Capacity
);
202 io
->io_Error
= IOERR_BADADDRESS
;
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
;
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
);
243 block
>>= unit
->au_SectorShift
;
244 count
>>= unit
->au_SectorShift
;
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
;
262 io
->io_Error
= unit
->au_Write32(unit
, (ULONG
)(block
& 0x0fffffff),
263 count
, IOStdReq(io
)->io_Data
, &cnt
);
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
,
273 block
>>32, block
&0xfffffffful
,
274 count
, unit
->au_Capacity48
>>32,
275 unit
->au_Capacity48
& 0xfffffffful
);
276 io
->io_Error
= IOERR_BADADDRESS
;
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__
));
298 while((msg
= (struct IORequest
*)GetMsg((struct MsgPort
*)bus
->ab_MsgPort
)))
300 msg
->io_Error
= IOERR_ABORTED
;
301 ReplyMsg((struct Message
*)msg
);
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
++;
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
;
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
;
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;
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;
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__
));
410 AddHead(&unit
->au_SoftList
, (struct Node
*)io
);
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__
));
422 Remove((struct Node
*)io
);
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;
453 dg
->dg_TotalSectors
= unit
->au_Capacity48
;
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;
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
)
500 if ((IOStdReq(io
)->io_Reserved1
) != (IOStdReq(io
)->io_Reserved2
))
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
;
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
;
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
;
536 static void cmd_SMART(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
538 struct ata_Unit
*unit
= (struct ata_Unit
*)io
->io_Unit
;
540 struct ata_Bus
*bus
= unit
->au_Bus
;
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
;
551 if (!ValidSMARTCmd(io
))
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
);
568 ata_SMARTCmd(IOStdReq(io
));
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__
));
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
);
595 ata_TRIMCmd(IOStdReq(io
));
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
[] = {
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
)
701 /* Handle few commands directly here */
702 switch (io
->io_Command
)
705 New Style Devices query. Introduce self as trackdisk and provide list of
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
);
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
725 case TD_GETDRIVETYPE
:
726 IOStdReq(io
)->io_Actual
= DRIVE_NEWSTYLE
;
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.
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
);
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
);
747 cmd_Invalid(io
, LIBBASE
);
749 else cmd_Invalid(io
, LIBBASE
);
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
))
769 else if ((io
->io_Command
>= HD_SMARTCMD
&& io
->io_Command
<= HD_TRIMCMD
) &&
770 (IOStdReq(io
)->io_Reserved1
== ATAFEATURE_TEST_AVAIL
)) slow
= FALSE
;
772 else if (io
->io_Command
== NSCMD_TD_SEEK64
|| io
->io_Command
== NSCMD_DEVICEQUERY
) slow
= FALSE
;
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
)
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 */
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.
803 unit
->au_Unit
.unit_flags
|= UNITF_ACTIVE
| UNITF_INTASK
;
804 io
->io_Flags
&= ~IOF_QUICK
;
807 /* Put the message to the bus */
808 PutMsg(unit
->au_Bus
->ab_MsgPort
, (struct Message
*)io
);
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
;
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__
));
835 AROS_LH1(LONG
, AbortIO
,
836 AROS_LHA(struct IORequest
*, io
, A1
),
837 LIBBASETYPEPTR
, LIBBASE
, 6, ata
)
841 /* Cannot Abort IO */
847 AROS_LH1(ULONG
, GetRdskLba
,
848 AROS_LHA(struct IORequest
*, io
, A1
),
849 LIBBASETYPEPTR
, LIBBASE
, 7, ata
)
858 AROS_LH1(ULONG
, GetBlkSize
,
859 AROS_LHA(struct IORequest
*, io
, A1
),
860 LIBBASETYPEPTR
, LIBBASE
, 8, ata
)
864 return Unit(io
)->au_SectorShift
;
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
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
883 D(bug("[ATA**] You woke up DAEMON\n"));
886 * Prepare message ports and timer.device's request
888 timer
= ata_OpenTimer(ATABase
);
891 D(bug("[ATA++] Failed to open timer!\n"));
894 Signal(ATABase
->daemonParent
, SIGF_SINGLE
);
898 /* Calibrate 400ns delay */
899 if (!ata_Calibrate(timer
, ATABase
))
901 ata_CloseTimer(timer
);
903 Signal(ATABase
->daemonParent
, SIGF_SINGLE
);
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"));
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
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"));
961 D(bug("[ATA++] Daemon quits\n"));
963 ata_CloseTimer(timer
);
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
)
978 struct IORequest
*msg
;
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
);
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
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
);
1040 ata_RegisterVolume(0, unit
->au_Cylinders
- 1, unit
);
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 */
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
)))
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
);