2 Copyright © 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/scsi.h>
31 #include LC_LIBDEFS_FILE
35 //---------------------------IO Commands---------------------------------------
37 /* Invalid comand does nothing, complains only. */
38 static void cmd_Invalid(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
40 D(bug("[SCSI%02ld] %s(%d)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, io
->io_Command
));
41 io
->io_Error
= IOERR_NOCMD
;
44 /* Don't need to reset the drive? */
45 static void cmd_Reset(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
47 IOStdReq(io
)->io_Actual
= 0;
50 /* CMD_READ implementation */
51 static void cmd_Read32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
53 struct scsi_Unit
*unit
= (struct scsi_Unit
*)IOStdReq(io
)->io_Unit
;
55 if (AF_Removable
== (unit
->su_Flags
& (AF_Removable
| AF_DiscPresent
)))
57 D(bug("[SCSI%02ld] %s: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit
->su_UnitNum
, __func__
));
58 io
->io_Error
= TDERR_DiskChanged
;
62 ULONG block
= IOStdReq(io
)->io_Offset
;
63 ULONG count
= IOStdReq(io
)->io_Length
;
65 D(bug("[SCSI%02ld] %s(%08x, %08x)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, block
, count
));
67 ULONG mask
= (1 << unit
->su_SectorShift
) - 1;
70 During this IO call it should be sure that both offset and
71 length are already aligned properly to sector boundaries.
73 if ((block
& mask
) | (count
& mask
))
75 D(bug("[SCSI%02ld] %s: offset or length not sector-aligned.\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
76 cmd_Invalid(io
, LIBBASE
);
80 block
>>= unit
->su_SectorShift
;
81 count
>>= unit
->su_SectorShift
;
84 if ((0 == (unit
->su_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->su_Capacity
))
86 bug("[SCSI%02ld] %s: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, block
, count
, unit
->su_Capacity
);
87 io
->io_Error
= IOERR_BADADDRESS
;
91 /* Call the Unit's access funtion */
92 io
->io_Error
= unit
->su_Read32(unit
, block
, count
,
93 IOStdReq(io
)->io_Data
, &cnt
);
95 IOStdReq(io
)->io_Actual
= cnt
;
100 NSCMD_TD_READ64, TD_READ64 implementation. Basically the same, just packs
101 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
103 static void cmd_Read64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
105 struct scsi_Unit
*unit
= (struct scsi_Unit
*)IOStdReq(io
)->io_Unit
;
107 if (AF_Removable
== (unit
->su_Flags
& (AF_Removable
| AF_DiscPresent
)))
109 D(bug("[SCSI%02ld] %s: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit
->su_UnitNum
, __func__
));
110 io
->io_Error
= TDERR_DiskChanged
;
114 UQUAD block
= IOStdReq(io
)->io_Offset
| (UQUAD
)(IOStdReq(io
)->io_Actual
) << 32;
115 ULONG count
= IOStdReq(io
)->io_Length
;
117 D(bug("[SCSI%02ld] %s(%08x-%08x, %08x)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, IOStdReq(io
)->io_Actual
, IOStdReq(io
)->io_Offset
, count
));
119 ULONG mask
= (1 << unit
->su_SectorShift
) - 1;
121 if ((block
& (UQUAD
)mask
) | (count
& mask
) | (count
== 0))
123 D(bug("[SCSI%02ld] %s: offset or length not sector-aligned.\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
124 cmd_Invalid(io
, LIBBASE
);
128 block
>>= unit
->su_SectorShift
;
129 count
>>= unit
->su_SectorShift
;
133 If the sum of sector offset and the sector count doesn't overflow
134 the 28-bit LBA address, use 32-bit access for speed and simplicity.
135 Otherwise do the 48-bit LBA addressing.
137 if ((block
+ count
) < 0x0fffffff)
139 if ((0 == (unit
->su_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->su_Capacity
))
141 bug("[SCSI%02ld] %s: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, block
, count
, unit
->su_Capacity
);
142 io
->io_Error
= IOERR_BADADDRESS
;
145 io
->io_Error
= unit
->su_Read32(unit
, (ULONG
)(block
& 0x0fffffff), count
, IOStdReq(io
)->io_Data
, &cnt
);
149 if ((0 == (unit
->su_XferModes
& AF_XFER_PACKET
)) && ((block
+ count
) > unit
->su_Capacity48
))
151 bug("[SCSI%02ld] %s: Requested block (%lx:%08lx;%ld) outside disk range (%lx:%08lx)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, block
>>32, block
&0xfffffffful
, count
, unit
->su_Capacity48
>>32, unit
->su_Capacity48
& 0xfffffffful
);
152 io
->io_Error
= IOERR_BADADDRESS
;
156 io
->io_Error
= unit
->su_Read64(unit
, block
, count
, IOStdReq(io
)->io_Data
, &cnt
);
159 IOStdReq(io
)->io_Actual
= cnt
;
163 /* CMD_WRITE implementation */
164 static void cmd_Write32(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
166 struct scsi_Unit
*unit
= (struct scsi_Unit
*)IOStdReq(io
)->io_Unit
;
168 if (AF_Removable
== (unit
->su_Flags
& (AF_Removable
| AF_DiscPresent
)))
170 D(bug("[SCSI%02ld] %s: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit
->su_UnitNum
, __func__
));
171 io
->io_Error
= TDERR_DiskChanged
;
175 ULONG block
= IOStdReq(io
)->io_Offset
;
176 ULONG count
= IOStdReq(io
)->io_Length
;
178 D(bug("[SCSI%02ld] %s(%08x, %08x)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, block
, count
));
180 ULONG mask
= (1 << unit
->su_SectorShift
) - 1;
183 During this IO call it should be sure that both offset and
184 length are already aligned properly to sector boundaries.
186 if ((block
& mask
) | (count
& mask
))
188 D(bug("[SCSI%02ld] %s: offset or length not sector-aligned.\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
189 cmd_Invalid(io
, LIBBASE
);
193 block
>>= unit
->su_SectorShift
;
194 count
>>= unit
->su_SectorShift
;
197 if ((0 == (unit
->su_XferModes
& AF_XFER_PACKET
))
198 && ((block
+ count
) > unit
->su_Capacity
))
200 bug("[SCSI%02ld] %s: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
,
202 block
, count
, unit
->su_Capacity
);
203 io
->io_Error
= IOERR_BADADDRESS
;
207 /* Call the Unit's access funtion */
208 io
->io_Error
= unit
->su_Write32(unit
, block
, count
,
209 IOStdReq(io
)->io_Data
, &cnt
);
211 IOStdReq(io
)->io_Actual
= cnt
;
216 NSCMD_TD_WRITE64, TD_WRITE64 implementation. Basically the same, just packs
217 the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32)
219 static void cmd_Write64(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
221 struct scsi_Unit
*unit
= (struct scsi_Unit
*)IOStdReq(io
)->io_Unit
;
223 if (AF_Removable
== (unit
->su_Flags
& (AF_Removable
| AF_DiscPresent
)))
225 D(bug("[SCSI%02ld] %s: USUALLY YOU'D WANT TO CHECK IF DISC IS PRESENT FIRST\n", unit
->su_UnitNum
, __func__
));
226 io
->io_Error
= TDERR_DiskChanged
;
230 UQUAD block
= IOStdReq(io
)->io_Offset
| (UQUAD
)(IOStdReq(io
)->io_Actual
) << 32;
231 ULONG count
= IOStdReq(io
)->io_Length
;
233 D(bug("[SCSI%02ld] %s(%08x-%08x, %08x)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, IOStdReq(io
)->io_Actual
, IOStdReq(io
)->io_Offset
, count
));
235 ULONG mask
= (1 << unit
->su_SectorShift
) - 1;
237 if ((block
& mask
) | (count
& mask
) | (count
==0))
239 D(bug("[SCSI%02ld] %s: offset or length not sector-aligned.\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
240 cmd_Invalid(io
, LIBBASE
);
244 block
>>= unit
->su_SectorShift
;
245 count
>>= unit
->su_SectorShift
;
249 If the sum of sector offset and the sector count doesn't overflow
250 the 28-bit LBA address, use 32-bit access for speed and simplicity.
251 Otherwise do the 48-bit LBA addressing.
253 if ((block
+ count
) < 0x0fffffff)
255 if ((0 == (unit
->su_XferModes
& AF_XFER_PACKET
))
256 && ((block
+ count
) > unit
->su_Capacity
))
258 bug("[SCSI%02ld] %s: Requested block (%lx;%ld) outside disk range "
259 "(%lx)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, block
, count
, unit
->su_Capacity
);
260 io
->io_Error
= IOERR_BADADDRESS
;
263 io
->io_Error
= unit
->su_Write32(unit
, (ULONG
)(block
& 0x0fffffff),
264 count
, IOStdReq(io
)->io_Data
, &cnt
);
268 if ((0 == (unit
->su_XferModes
& AF_XFER_PACKET
))
269 && ((block
+ count
) > unit
->su_Capacity48
))
271 bug("[SCSI%02ld] %s: Requested block (%lx:%08lx;%ld) outside disk "
272 "range (%lx:%08lx)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
,
274 block
>>32, block
&0xfffffffful
,
275 count
, unit
->su_Capacity48
>>32,
276 unit
->su_Capacity48
& 0xfffffffful
);
277 io
->io_Error
= IOERR_BADADDRESS
;
281 io
->io_Error
= unit
->su_Write64(unit
, block
, count
,
282 IOStdReq(io
)->io_Data
, &cnt
);
284 IOStdReq(io
)->io_Actual
= cnt
;
289 /* use CMD_FLUSH to force all IO waiting commands to abort */
290 static void cmd_Flush(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
292 struct IORequest
*msg
;
293 struct scsi_Bus
*bus
= ((struct scsi_Unit
*)io
->io_Unit
)->su_Bus
;
295 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
299 while((msg
= (struct IORequest
*)GetMsg((struct MsgPort
*)bus
->sb_MsgPort
)))
301 msg
->io_Error
= IOERR_ABORTED
;
302 ReplyMsg((struct Message
*)msg
);
309 Internal command used to check whether the media in drive has been changed
310 since last call. If so, the handlers given by user are called.
312 static void cmd_TestChanged(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
314 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
315 struct IORequest
*msg
;
317 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
319 if ((unit
->su_XferModes
& AF_XFER_PACKET
) && (unit
->su_Flags
& AF_Removable
))
322 atapi_TestUnitOK(unit
);
324 if (unit
->su_Flags
& AF_DiscChanged
)
326 unit
->su_ChangeNum
++;
330 /* old-fashioned RemoveInt call first */
331 if (unit
->su_RemoveInt
)
332 Cause(unit
->su_RemoveInt
);
334 /* And now the whole list of possible calls */
335 ForeachNode(&unit
->su_SoftList
, msg
)
337 Cause((struct Interrupt
*)IOStdReq(msg
)->io_Data
);
340 unit
->su_Flags
&= ~AF_DiscChanged
;
347 static void cmd_Update(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
349 /* Do nothing now. In near future there should be drive cache flush though */
350 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
353 static void cmd_Remove(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
355 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
357 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
359 if (unit
->su_RemoveInt
)
360 io
->io_Error
= TDERR_DriveInUse
;
362 unit
->su_RemoveInt
= IOStdReq(io
)->io_Data
;
365 static void cmd_ChangeNum(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
367 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
369 IOStdReq(io
)->io_Actual
= ((struct scsi_Unit
*)io
->io_Unit
)->su_ChangeNum
;
372 static void cmd_ChangeState(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
374 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
376 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
378 if (unit
->su_Flags
& AF_DiscPresent
)
379 IOStdReq(io
)->io_Actual
= 0;
381 IOStdReq(io
)->io_Actual
= 1;
383 D(bug("[SCSI%02ld] %s: Media %s\n", unit
->su_UnitNum
, __func__
, IOStdReq(io
)->io_Actual
? "ABSENT" : "PRESENT"));
386 static void cmd_ProtStatus(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
388 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
390 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
392 if (unit
->su_DevType
)
393 IOStdReq(io
)->io_Actual
= -1;
395 IOStdReq(io
)->io_Actual
= 0;
399 static void cmd_GetNumTracks(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
401 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
403 IOStdReq(io
)->io_Actual
= ((struct scsi_Unit
*)io
->io_Unit
)->su_Cylinders
;
406 static void cmd_AddChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
408 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
410 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
413 AddHead(&unit
->su_SoftList
, (struct Node
*)io
);
416 io
->io_Flags
&= ~IOF_QUICK
;
417 unit
->su_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
420 static void cmd_RemChangeInt(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
422 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
425 Remove((struct Node
*)io
);
429 static void cmd_Eject(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
431 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
433 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
435 IOStdReq(io
)->io_Error
= unit
->su_Eject(unit
);
436 cmd_TestChanged(io
, LIBBASE
);
439 static void cmd_GetGeometry(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
441 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
443 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
445 if (IOStdReq(io
)->io_Length
== sizeof(struct DriveGeometry
))
447 struct DriveGeometry
*dg
= (struct DriveGeometry
*)IOStdReq(io
)->io_Data
;
449 dg
->dg_SectorSize
= 1 << unit
->su_SectorShift
;
451 if (unit
->su_Capacity48
!= 0)
453 if ((unit
->su_Capacity48
>> 32) != 0)
454 dg
->dg_TotalSectors
= 0xffffffff;
456 dg
->dg_TotalSectors
= unit
->su_Capacity48
;
459 dg
->dg_TotalSectors
= unit
->su_Capacity
;
461 dg
->dg_Cylinders
= unit
->su_Cylinders
;
462 dg
->dg_CylSectors
= unit
->su_Sectors
* unit
->su_Heads
;
463 dg
->dg_Heads
= unit
->su_Heads
;
464 dg
->dg_TrackSectors
= unit
->su_Sectors
;
465 dg
->dg_BufMemType
= MEMF_PUBLIC
;
466 dg
->dg_DeviceType
= unit
->su_DevType
;
467 if (dg
->dg_DeviceType
!= DG_DIRECT_ACCESS
)
468 dg
->dg_Flags
= (unit
->su_Flags
& AF_Removable
) ? DGF_REMOVABLE
: 0;
473 IOStdReq(io
)->io_Actual
= sizeof(struct DriveGeometry
);
475 else if (IOStdReq(io
)->io_Length
== 514)
477 CopyMemQuick(unit
->su_Drive
, IOStdReq(io
)->io_Data
, 512);
479 else io
->io_Error
= TDERR_NotSpecified
;
482 static void cmd_DirectScsi(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
484 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
486 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
488 IOStdReq(io
)->io_Actual
= sizeof(struct SCSICmd
);
490 if (unit
->su_XferModes
& AF_XFER_PACKET
)
492 io
->io_Error
= unit
->su_DirectSCSI(unit
, (struct SCSICmd
*)IOStdReq(io
)->io_Data
);
494 else if (unit
->su_DevType
== DG_DIRECT_ACCESS
)
496 io
->io_Error
= SCSIEmu(unit
, (struct SCSICmd
*)IOStdReq(io
)->io_Data
);
498 else io
->io_Error
= IOERR_BADADDRESS
;
500 io
->io_Error
= IOERR_BADADDRESS
;
504 static BOOL
ValidSMARTCmd(struct IORequest
*io
)
507 if ((IOStdReq(io
)->io_Reserved1
) != (IOStdReq(io
)->io_Reserved2
))
510 switch (IOStdReq(io
)->io_Reserved1
)
512 case SMARTC_TEST_AVAIL
:
513 case SMARTC_READ_VALUES
:
514 case SMARTC_READ_THRESHOLDS
:
515 if (!IOStdReq(io
)->io_Data
)
517 D(bug("[SCSI%02ld] %s: invalid io_Data (%p)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, IOStdReq(io
)->io_Data
));
518 io
->io_Error
= IOERR_BADADDRESS
;
521 if ((IOStdReq(io
)->io_Offset
!= SMARTC_TEST_AVAIL
) && (IOStdReq(io
)->io_Length
!= SMART_DSCSI_LENGTH
))
523 D(bug("[SCSI%02ld] %s: invalid io_Length (%d)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, IOStdReq(io
)->io_Length
));
524 io
->io_Error
= IOERR_BADLENGTH
;
535 D(bug("[SCSI%02ld] %s: invalid SMART command (%d)\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, IOStdReq(io
)->io_Offset
));
536 io
->io_Error
= IOERR_NOCMD
;
543 static void cmd_SMART(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
545 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
547 struct scsi_Bus
*bus
= unit
->su_Bus
;
550 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
552 if (unit
->su_Flags
& AF_DiscPresent
)
554 io
->io_Error
= IOERR_OPENFAIL
;
558 if (!ValidSMARTCmd(io
))
561 u
= unit
->su_UnitNum
& 1;
563 if (bus
->sb_Dev
[u
] == DEV_ATA
|| bus
->sb_Dev
[u
] == DEV_SATA
)
565 if (IOStdReq(io
)->io_Reserved1
== ATAFEATURE_TEST_AVAIL
)
567 if (IOStdReq(io
)->io_Length
>= sizeof(ULONG
))
569 *((ULONG
*)IOStdReq(io
)->io_Data
) = SMART_MAGIC_ID
;
570 IOStdReq(io
)->io_Actual
= sizeof(ULONG
);
575 scsi_SMARTCmd(IOStdReq(io
));
579 io
->io_Error
= IOERR_NOCMD
;
582 static void cmd_TRIM(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
584 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
586 D(bug("[SCSI%02ld] %s()\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
588 if ((unit
->su_Drive
->id_SCSIVersion
>= 7) && (unit
->su_Drive
->id_DSManagement
& 1))
590 D(bug("[SCSI%02ld] %s: Unit supports TRIM\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
592 if (IOStdReq(io
)->io_Reserved1
== ATAFEATURE_TEST_AVAIL
)
594 if (IOStdReq(io
)->io_Length
>= sizeof(ULONG
))
596 *((ULONG
*)IOStdReq(io
)->io_Data
) = TRIM_MAGIC_ID
;
597 IOStdReq(io
)->io_Actual
= sizeof(ULONG
);
602 scsi_TRIMCmd(IOStdReq(io
));
606 io
->io_Error
= IOERR_NOCMD
;
609 //-----------------------------------------------------------------------------
612 command translation tables - used to call proper IO functions.
615 #define N_TD_READ64 0
616 #define N_TD_WRITE64 1
617 #define N_TD_SEEK64 2
618 #define N_TD_FORMAT64 3
620 typedef void (*mapfunc
)(struct IORequest
*, LIBBASETYPEPTR
);
622 static mapfunc
const map64
[]= {
623 [N_TD_READ64
] = cmd_Read64
,
624 [N_TD_WRITE64
] = cmd_Write64
,
625 [N_TD_SEEK64
] = cmd_Reset
,
626 [N_TD_FORMAT64
] = cmd_Write64
629 static mapfunc
const map32
[] = {
630 [CMD_INVALID
] = cmd_Invalid
,
631 [CMD_RESET
] = cmd_Reset
,
632 [CMD_READ
] = cmd_Read32
,
633 [CMD_WRITE
] = cmd_Write32
,
634 [CMD_UPDATE
] = cmd_Update
,
635 [CMD_CLEAR
] = cmd_Reset
,
636 [CMD_STOP
] = cmd_Reset
,
637 [CMD_START
] = cmd_Reset
,
638 [CMD_FLUSH
] = cmd_Flush
,
639 [TD_MOTOR
] = cmd_Reset
,
640 [TD_SEEK
] = cmd_Reset
,
641 [TD_FORMAT
] = cmd_Write32
,
642 [TD_REMOVE
] = cmd_Remove
,
643 [TD_CHANGENUM
] = cmd_ChangeNum
,
644 [TD_CHANGESTATE
]= cmd_ChangeState
,
645 [TD_PROTSTATUS
] = cmd_ProtStatus
,
646 [TD_RAWREAD
] = cmd_Invalid
,
647 [TD_RAWWRITE
] = cmd_Invalid
,
648 [TD_GETNUMTRACKS
] = cmd_GetNumTracks
,
649 [TD_ADDCHANGEINT
] = cmd_AddChangeInt
,
650 [TD_REMCHANGEINT
] = cmd_RemChangeInt
,
651 [TD_GETGEOMETRY
]= cmd_GetGeometry
,
652 [TD_EJECT
] = cmd_Eject
,
653 [TD_READ64
] = cmd_Read64
,
654 [TD_WRITE64
] = cmd_Write64
,
655 [TD_SEEK64
] = cmd_Reset
,
656 [TD_FORMAT64
] = cmd_Write64
,
657 [HD_SCSICMD
] = cmd_DirectScsi
,
658 [HD_SCSICMD
+1] = cmd_TestChanged
661 static UWORD
const NSDSupported
[] = {
697 Do proper IO actions depending on the request. It's called from the bus
698 tasks and from BeginIO in case of immediate commands.
700 static void HandleIO(struct IORequest
*io
, LIBBASETYPEPTR LIBBASE
)
704 /* Handle few commands directly here */
705 switch (io
->io_Command
)
708 New Style Devices query. Introduce self as trackdisk and provide list of
711 case NSCMD_DEVICEQUERY
:
713 struct NSDeviceQueryResult
*nsdq
= (struct NSDeviceQueryResult
*)IOStdReq(io
)->io_Data
;
714 nsdq
->DevQueryFormat
= 0;
715 nsdq
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
716 nsdq
->DeviceType
= NSDEVTYPE_TRACKDISK
;
717 nsdq
->DeviceSubType
= 0;
718 nsdq
->SupportedCommands
= (UWORD
*)NSDSupported
;
720 IOStdReq(io
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
724 New Style Devices report here the 'NSTY' - only if such value is
725 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
728 case TD_GETDRIVETYPE
:
729 IOStdReq(io
)->io_Actual
= DRIVE_NEWSTYLE
;
733 Call all other commands using the command pointer tables for 32- and
734 64-bit accesses. If requested function is defined call it, otherwise
735 make the function cmd_Invalid.
738 if (io
->io_Command
<= (HD_SCSICMD
+1))
740 if (map32
[io
->io_Command
])
741 map32
[io
->io_Command
](io
, LIBBASE
);
743 cmd_Invalid(io
, LIBBASE
);
745 else if (io
->io_Command
>= NSCMD_TD_READ64
&& io
->io_Command
<= NSCMD_TD_FORMAT64
)
747 if (map64
[io
->io_Command
- NSCMD_TD_READ64
])
748 map64
[io
->io_Command
- NSCMD_TD_READ64
](io
, LIBBASE
);
750 cmd_Invalid(io
, LIBBASE
);
752 else cmd_Invalid(io
, LIBBASE
);
758 static const ULONG IMMEDIATE_COMMANDS
= 0x803ff1e3; // 10000000001111111111000111100011
760 /* See whether the command can be done quick */
761 static BOOL
isSlow(struct IORequest
*io
)
763 BOOL slow
= TRUE
; /* Assume always slow command */
765 /* For commands with numbers <= 31 check the mask */
766 if (io
->io_Command
<= 31)
768 if (IMMEDIATE_COMMANDS
& (1 << io
->io_Command
))
772 else if ((io
->io_Command
>= HD_SMARTCMD
&& io
->io_Command
<= HD_TRIMCMD
) &&
773 (IOStdReq(io
)->io_Reserved1
== ATAFEATURE_TEST_AVAIL
)) slow
= FALSE
;
775 else if (io
->io_Command
== NSCMD_TD_SEEK64
|| io
->io_Command
== NSCMD_DEVICEQUERY
) slow
= FALSE
;
781 Try to do IO commands. All commands which require talking with scsi devices
782 will be handled slow, that is they will be passed to bus task which will
783 execute them as soon as hardware will be free.
785 AROS_LH1(void, BeginIO
,
786 AROS_LHA(struct IORequest
*, io
, A1
),
787 LIBBASETYPEPTR
, LIBBASE
, 5, scsi
)
791 struct scsi_Unit
*unit
= (struct scsi_Unit
*)io
->io_Unit
;
793 io
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
795 /* Disable interrupts for a while to modify message flags */
798 D(bug("[SCSI%02ld] %s: Executing IO Command %lx\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
, io
->io_Command
));
801 If the command is not-immediate, or presence of disc is still unknown,
802 let the bus task do the job.
806 unit
->su_Unit
.unit_flags
|= UNITF_ACTIVE
| UNITF_INTASK
;
807 io
->io_Flags
&= ~IOF_QUICK
;
810 /* Put the message to the bus */
811 PutMsg(unit
->su_Bus
->sb_MsgPort
, (struct Message
*)io
);
815 D(bug("[SCSI%02ld] %s: ->Fast command\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
817 /* Immediate command. Mark unit as active and do the command directly */
818 unit
->su_Unit
.unit_flags
|= UNITF_ACTIVE
;
820 HandleIO(io
, LIBBASE
);
822 unit
->su_Unit
.unit_flags
&= ~UNITF_ACTIVE
;
825 If the command was not intended to be immediate and it was not the
826 TD_ADDCHANGEINT, reply to confirm command execution now.
828 if (!(io
->io_Flags
& IOF_QUICK
) && (io
->io_Command
!= TD_ADDCHANGEINT
))
830 ReplyMsg((struct Message
*)io
);
834 D(bug("[SCSI%02ld] %s: Done\n", ((struct scsi_Unit
*)io
->io_Unit
)->su_UnitNum
, __func__
));
838 AROS_LH1(LONG
, AbortIO
,
839 AROS_LHA(struct IORequest
*, io
, A1
),
840 LIBBASETYPEPTR
, LIBBASE
, 6, scsi
)
844 /* Cannot Abort IO */
850 AROS_LH1(ULONG
, GetRdskLba
,
851 AROS_LHA(struct IORequest
*, io
, A1
),
852 LIBBASETYPEPTR
, LIBBASE
, 7, scsi
)
861 AROS_LH1(ULONG
, GetBlkSize
,
862 AROS_LHA(struct IORequest
*, io
, A1
),
863 LIBBASETYPEPTR
, LIBBASE
, 8, scsi
)
867 return Unit(io
)->su_SectorShift
;
873 * The daemon of scsi.device first opens all ATAPI devices and then enters
874 * endless loop. Every 2 seconds it tells ATAPI units to check the media
875 * presence. In case of any state change they will rise user-specified
877 * The check is done by sending HD_SCSICMD+1 command (internal testchanged
878 * command). ATAPI units should already handle the command further.
880 void DaemonCode(LIBBASETYPEPTR LIBBASE
)
882 struct IORequest
*timer
; // timer
886 D(bug("[SCSI**] You woke up DAEMON\n"));
889 * Prepare message ports and timer.device's request
891 timer
= scsi_OpenTimer(LIBBASE
);
894 D(bug("[SCSI++] Failed to open timer!\n"));
897 Signal(LIBBASE
->daemonParent
, SIGF_SINGLE
);
901 /* Calibrate 400ns delay */
902 if (!scsi_Calibrate(timer
, LIBBASE
))
904 scsi_CloseTimer(timer
);
906 Signal(LIBBASE
->daemonParent
, SIGF_SINGLE
);
910 /* This also signals that we have initialized successfully */
911 LIBBASE
->scsi_Daemon
= FindTask(NULL
);
912 Signal(LIBBASE
->daemonParent
, SIGF_SINGLE
);
914 D(bug("[SCSI++] Starting sweep medium presence detection\n"));
922 * call separate IORequest for every ATAPI device
923 * we're calling HD_SCSICMD+1 command here -- anything like test unit ready?
924 * FIXME: This is not a very nice approach in terms of performance.
925 * This inserts own command into command queue every 2 seconds, so
926 * this would give periodic performance drops under high loads.
927 * It would be much better if unit tasks ping their devices by themselves,
928 * when idle. This would also save us from lots of headaches with dealing
929 * with list of these requests. Additionally i start disliking all these
934 struct IOStdReq
*ios
;
936 DB2(bug("[SCSI++] Detecting media presence\n"));
937 ObtainSemaphore(&LIBBASE
->DaemonSem
);
939 ForeachNode(&LIBBASE
->Daemon_ios
, ios
)
941 /* Using the request will clobber its Node. Save links. */
942 struct Node
*s
= ios
->io_Message
.mn_Node
.ln_Succ
;
943 struct Node
*p
= ios
->io_Message
.mn_Node
.ln_Pred
;
945 DoIO((struct IORequest
*)ios
);
947 ios
->io_Message
.mn_Node
.ln_Succ
= s
;
948 ios
->io_Message
.mn_Node
.ln_Pred
= p
;
951 ReleaseSemaphore(&LIBBASE
->DaemonSem
);
955 * And then hide and wait for 1 second
957 DB2(bug("[SCSI++] 1 second delay, timer 0x%p...\n", timer
));
958 sigs
= scsi_WaitTO(timer
, 1, 0, SIGBREAKF_CTRL_C
);
960 DB2(bug("[SCSI++] Delay completed\n"));
964 D(bug("[SCSI++] Daemon quits\n"));
966 scsi_CloseTimer(timer
);
969 Signal(LIBBASE
->daemonParent
, SIGF_SINGLE
);
973 Bus task body. It doesn't really do much. It receives simply all IORequests
974 in endless loop and calls proper handling function. The IO is Semaphore-
975 protected within a bus.
977 void BusTaskCode(struct scsi_Bus
*bus
, LIBBASETYPEPTR LIBBASE
)
981 struct IORequest
*msg
;
983 struct scsi_Unit
*unit
;
985 DINIT(bug("[SCSI**] Task started (bus: %u)\n", bus
->sb_BusNum
));
987 bus
->sb_Timer
= scsi_OpenTimer(LIBBASE
);
988 bus
->sb_BounceBufferPool
= CreatePool(MEMF_CLEAR
| MEMF_31BIT
, 131072, 65536);
990 /* Get the signal used for sleeping */
991 bus
->sb_Task
= FindTask(0);
992 bus
->sb_SleepySignal
= AllocSignal(-1);
993 /* Failed to get it? Use SIGBREAKB_CTRL_E instead */
994 if (bus
->sb_SleepySignal
< 0)
995 bus
->sb_SleepySignal
= SIGBREAKB_CTRL_E
;
997 sig
= 1L << bus
->sb_MsgPort
->mp_SigBit
;
999 for (iter
= 0; iter
< MAX_BUSUNITS
; ++iter
)
1001 DINIT(bug("[SCSI**] Device %u type %d\n", iter
, bus
->sb_Dev
[iter
]));
1003 if (bus
->sb_Dev
[iter
] > DEV_UNKNOWN
)
1005 unitObj
= OOP_NewObject(LIBBASE
->unitClass
, NULL
, NULL
);
1008 unit
= OOP_INST_DATA(LIBBASE
->unitClass
, unitObj
);
1009 scsi_init_unit(bus
, unit
, iter
);
1010 if (scsi_setup_unit(bus
, unit
))
1013 * Add unit to the bus.
1014 * At this point it becomes visible to OpenDevice().
1016 bus
->sb_Units
[iter
] = unitObj
;
1018 if (unit
->su_XferModes
& AF_XFER_PACKET
)
1020 scsi_RegisterVolume(0, 0, unit
);
1022 /* For ATAPI device we also submit media presence detection request */
1023 unit
->DaemonReq
= (struct IOStdReq
*)CreateIORequest(LIBBASE
->DaemonPort
, sizeof(struct IOStdReq
));
1024 if (unit
->DaemonReq
)
1027 * We don't want to keep stalled open count of 1, so we
1028 * don't call OpenDevice() here. Instead we fill in the needed
1031 unit
->DaemonReq
->io_Device
= &LIBBASE
->scsi_Device
;
1032 unit
->DaemonReq
->io_Unit
= &unit
->su_Unit
;
1033 unit
->DaemonReq
->io_Command
= HD_SCSICMD
+1;
1035 ObtainSemaphore(&LIBBASE
->DaemonSem
);
1036 AddTail((struct List
*)&LIBBASE
->Daemon_ios
,
1037 &unit
->DaemonReq
->io_Message
.mn_Node
);
1038 ReleaseSemaphore(&LIBBASE
->DaemonSem
);
1043 scsi_RegisterVolume(0, unit
->su_Cylinders
- 1, unit
);
1048 /* Destroy unit that couldn't be initialised */
1049 OOP_DisposeObject((OOP_Object
*)unit
);
1050 bus
->sb_Dev
[iter
] = DEV_NONE
;
1056 D(bug("[SCSI--] Bus %u scan finished\n", bus
->sb_BusNum
));
1057 ReleaseSemaphore(&LIBBASE
->DetectionSem
);
1059 /* Wait forever and process messages */
1064 /* Even if you get new signal, do not process it until Unit is not active */
1065 if (!(bus
->sb_Flags
& UNITF_ACTIVE
))
1067 bus
->sb_Flags
|= UNITF_ACTIVE
;
1069 /* Empty the request queue */
1070 while ((msg
= (struct IORequest
*)GetMsg(bus
->sb_MsgPort
)))
1073 HandleIO(msg
, LIBBASE
);
1074 /* TD_ADDCHANGEINT doesn't require reply */
1075 if (msg
->io_Command
!= TD_ADDCHANGEINT
)
1077 ReplyMsg((struct Message
*)msg
);
1081 bus
->sb_Flags
&= ~(UNITF_INTASK
| UNITF_ACTIVE
);