2 Copyright © 2004-2018, The AROS Development Team. All rights reserved
9 /* Maintainer: Jason S. McMullan <jason.mcmullan@gmail.com>
12 #include <aros/debug.h>
14 #include <proto/exec.h>
16 /* We want all other bases obtained from our base */
19 #include <aros/atomic.h>
20 #include <aros/symbolsets.h>
21 #include <exec/exec.h>
22 #include <exec/resident.h>
23 #include <exec/tasks.h>
24 #include <exec/memory.h>
25 #include <exec/nodes.h>
26 #include <utility/utility.h>
27 #include <libraries/expansion.h>
28 #include <libraries/configvars.h>
29 #include <devices/trackdisk.h>
30 #include <devices/newstyle.h>
32 #include <dos/dosextens.h>
33 #include <dos/filehandler.h>
35 #include <proto/timer.h>
36 #include <proto/bootloader.h>
37 #include <proto/expansion.h>
38 #include <proto/oop.h>
45 #include "ahci_scsi.h"
48 #include LC_LIBDEFS_FILE
50 /* Translate to a SCSI command, since the
51 * backend will make that work on both ATAPI
54 * Return whether or not we are completed.
56 static BOOL
ahci_sector_rw(struct IORequest
*io
, UQUAD off64
, BOOL is_write
)
58 struct IOExtTD
*iotd
= (struct IOExtTD
*)io
;
59 struct cam_sim
*unit
= (struct cam_sim
*)io
->io_Unit
;
60 struct ahci_port
*ap
= unit
->sim_Port
;
61 struct ata_port
*at
= ap
->ap_ata
[0];
62 APTR data
= iotd
->iotd_Req
.io_Data
;
63 ULONG len
= iotd
->iotd_Req
.io_Length
;
64 ULONG sector_size
, bmask
;
66 /* It's safe to allocate these on the stack, since they
67 * will never be referenced once the ahci_scsi_*_io()
70 struct SCSICmd scsi
= {};
71 union scsi_cdb cdb
= {};
73 if (ap
->ap_type
== ATA_PORT_T_DISK
) {
74 sector_size
= at
->at_identify
.sector_size
;
75 } else if (ap
->ap_type
== ATA_PORT_T_ATAPI
) {
76 // FIXME: Where should this come from?
79 io
->io_Error
= TDERR_DiskChanged
;
82 bmask
= sector_size
- 1;
84 if ((off64
& bmask
) || bmask
== 0 || data
== NULL
) {
85 io
->io_Error
= IOERR_BADADDRESS
;
88 if ((len
& bmask
) || len
== 0) {
89 D(bug("[AHCI%02ld] IO %p Fault, io_Flags = %d, io_Command = %d, IOERR_BADLENGTH (len=0x%x, bmask=0x%x)\n", unit
->sim_Unit
, io
, io
->io_Flags
, io
->io_Command
, len
, bmask
));
90 io
->io_Error
= IOERR_BADLENGTH
;
95 IOStdReq(io
)->io_Actual
= 0;
99 scsi
.scsi_Data
= data
;
100 scsi
.scsi_Length
= len
;
101 scsi
.scsi_Flags
= is_write
? SCSIF_WRITE
: SCSIF_READ
;
103 /* Make in units of sector size */
105 off64
/= sector_size
;
107 /* Set up the CDB, based on what the transfer size is */
108 scsi
.scsi_Command
= (APTR
)&cdb
;
110 if (off64
< (1 << 21) && len
< (1 << 8)) {
111 cdb
.rw_6
.opcode
= is_write
? SCSI_DA_WRITE_6
: SCSI_DA_READ_6
;
112 cdb
.rw_6
.addr
[0] = (off64
>> 16) & 0x1f;
113 cdb
.rw_6
.addr
[1] = (off64
>> 8) & 0xff;
114 cdb
.rw_6
.addr
[2] = (off64
>> 0) & 0xff;
115 cdb
.rw_6
.length
= len
;
116 scsi
.scsi_CmdLength
= sizeof(cdb
.rw_6
);
117 } else if (off64
< (1ULL << 32) && len
< (1 << 16)) {
118 cdb
.rw_10
.opcode
= is_write
? SCSI_DA_WRITE_10
: SCSI_DA_READ_10
;
119 cdb
.rw_10
.addr
[0] = (off64
>> 24) & 0xff;
120 cdb
.rw_10
.addr
[1] = (off64
>> 16) & 0xff;
121 cdb
.rw_10
.addr
[2] = (off64
>> 8) & 0xff;
122 cdb
.rw_10
.addr
[3] = (off64
>> 0) & 0xff;
123 cdb
.rw_10
.length
[0] = (len
>> 8) & 0xff;
124 cdb
.rw_10
.length
[1] = (len
>> 0) & 0xff;
125 scsi
.scsi_CmdLength
= sizeof(cdb
.rw_10
);
126 } else if (off64
< (1ULL << 32)) {
127 cdb
.rw_12
.opcode
= is_write
? SCSI_DA_WRITE_12
: SCSI_DA_READ_12
;
128 cdb
.rw_12
.addr
[0] = (off64
>> 24) & 0xff;
129 cdb
.rw_12
.addr
[1] = (off64
>> 16) & 0xff;
130 cdb
.rw_12
.addr
[2] = (off64
>> 8) & 0xff;
131 cdb
.rw_12
.addr
[3] = (off64
>> 0) & 0xff;
132 cdb
.rw_12
.length
[0] = (len
>> 24) & 0xff;
133 cdb
.rw_12
.length
[1] = (len
>> 16) & 0xff;
134 cdb
.rw_12
.length
[2] = (len
>> 8) & 0xff;
135 cdb
.rw_12
.length
[3] = (len
>> 0) & 0xff;
136 scsi
.scsi_CmdLength
= sizeof(cdb
.rw_12
);
138 cdb
.rw_16
.opcode
= is_write
? SCSI_DA_WRITE_16
: SCSI_DA_READ_16
;
139 cdb
.rw_16
.addr
[0] = (off64
>> 56) & 0xff;
140 cdb
.rw_16
.addr
[1] = (off64
>> 48) & 0xff;
141 cdb
.rw_16
.addr
[2] = (off64
>> 40) & 0xff;
142 cdb
.rw_16
.addr
[3] = (off64
>> 32) & 0xff;
143 cdb
.rw_16
.addr
[4] = (off64
>> 24) & 0xff;
144 cdb
.rw_16
.addr
[5] = (off64
>> 16) & 0xff;
145 cdb
.rw_16
.addr
[6] = (off64
>> 8) & 0xff;
146 cdb
.rw_16
.addr
[7] = (off64
>> 0) & 0xff;
147 cdb
.rw_16
.length
[0] = (len
>> 24) & 0xff;
148 cdb
.rw_16
.length
[1] = (len
>> 16) & 0xff;
149 cdb
.rw_16
.length
[2] = (len
>> 8) & 0xff;
150 cdb
.rw_16
.length
[3] = (len
>> 0) & 0xff;
151 scsi
.scsi_CmdLength
= sizeof(cdb
.rw_16
);
154 if (ap
->ap_type
== ATA_PORT_T_DISK
)
155 done
= ahci_scsi_disk_io(io
, &scsi
);
156 else if (ap
->ap_type
== ATA_PORT_T_ATAPI
)
157 done
= ahci_scsi_atapi_io(io
, &scsi
);
159 io
->io_Error
= IOERR_NOCMD
;
165 Try to do IO commands. All commands which require talking with ahci devices
166 will be handled slow, that is they will be passed to bus task which will
167 execute them as soon as hardware will be free.
169 AROS_LH1(void, BeginIO
,
170 AROS_LHA(struct IORequest
*, io
, A1
),
171 LIBBASETYPEPTR
, LIBBASE
, 5, ahci
)
175 const UWORD NSDSupported
[] = {
196 struct IOExtTD
*iotd
= (struct IOExtTD
*)io
;
197 struct cam_sim
*unit
= (struct cam_sim
*)io
->io_Unit
;
198 struct ahci_port
*ap
= unit
->sim_Port
;
199 struct ata_port
*at
= ap
->ap_ata
[0];
200 APTR data
= iotd
->iotd_Req
.io_Data
;
201 ULONG len
= iotd
->iotd_Req
.io_Length
;
203 struct DriveGeometry
*geom
;
204 struct NSDeviceQueryResult
*nsqr
;
205 BOOL done
= (io
->io_Flags
& IOF_QUICK
) ? TRUE
: FALSE
;
207 io
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
210 D(bug("[AHCI%02ld] IO %p Start, io_Flags = %d, io_Command = %d\n", unit
->sim_Unit
, io
, io
->io_Flags
, io
->io_Command
));
212 /* Unit going offline? Don't permit new commands. */
213 if (unit
->sim_Flags
& SIMF_OffLine
) {
214 io
->io_Error
= IOERR_OPENFAIL
;
215 if (!(io
->io_Flags
& IOF_QUICK
))
216 ReplyMsg(&io
->io_Message
);
220 ObtainSemaphore(&unit
->sim_Lock
);
221 AddHead(&unit
->sim_IOs
, &io
->io_Message
.mn_Node
);
222 ReleaseSemaphore(&unit
->sim_Lock
);
224 switch (io
->io_Command
) {
225 case NSCMD_DEVICEQUERY
:
226 if (len
< sizeof(*nsqr
))
230 nsqr
->DevQueryFormat
= 0;
231 nsqr
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
232 nsqr
->DeviceType
= NSDEVTYPE_TRACKDISK
;
233 nsqr
->DeviceSubType
= 0;
234 nsqr
->SupportedCommands
= (UWORD
*)NSDSupported
;
235 IOStdReq(io
)->io_Actual
= sizeof(*nsqr
);
239 IOStdReq(io
)->io_Actual
= (ap
->ap_type
== ATA_PORT_T_DISK
) ? 0 : -1;
243 IOStdReq(io
)->io_Actual
= unit
->sim_ChangeNum
;
247 IOStdReq(io
)->io_Actual
= (unit
->sim_Flags
& SIMF_MediaPresent
) ? 0 : -1;
252 if (at
->at_identify
.config
& (1 << 7))
254 // FIXME: Eject removable media
259 case TD_GETDRIVETYPE
:
260 IOStdReq(io
)->io_Actual
= DRIVE_NEWSTYLE
;
264 if (len
< sizeof(*geom
))
267 if (ap
->ap_type
!= ATA_PORT_T_DISK
&& ap
->ap_type
!= ATA_PORT_T_ATAPI
)
271 memset(geom
, 0, len
);
272 if (ap
->ap_type
== ATA_PORT_T_DISK
) {
273 geom
->dg_SectorSize
= at
->at_identify
.sector_size
;
274 geom
->dg_TotalSectors
= 0;
275 geom
->dg_Cylinders
= at
->at_identify
.ncyls
;
276 geom
->dg_CylSectors
= at
->at_identify
.nsectors
* at
->at_identify
.nheads
;
277 geom
->dg_Heads
= at
->at_identify
.nheads
;
278 geom
->dg_TrackSectors
= at
->at_identify
.nsectors
;
280 geom
->dg_BufMemType
= MEMF_PUBLIC
;
281 geom
->dg_DeviceType
= (ap
->ap_type
== ATA_PORT_T_ATAPI
) ? DG_CDROM
: DG_DIRECT_ACCESS
;
282 geom
->dg_Flags
= (at
->at_identify
.config
& (1 << 7)) ? DGF_REMOVABLE
: 0;
283 IOStdReq(io
)->io_Actual
= sizeof(*geom
);
287 if (len
& (at
->at_identify
.nsectors
* at
->at_identify
.sector_size
- 1))
289 off64
= iotd
->iotd_Req
.io_Offset
;
290 if (off64
& (at
->at_identify
.nsectors
* at
->at_identify
.sector_size
- 1))
292 done
= ahci_sector_rw(io
, off64
, TRUE
);
295 // FIXME: Tie in with power management
296 IOStdReq(io
)->io_Actual
= 1;
300 off64
= iotd
->iotd_Req
.io_Offset
;
301 done
= ahci_sector_rw(io
, off64
, TRUE
);
304 case NSCMD_TD_WRITE64
:
305 off64
= iotd
->iotd_Req
.io_Offset
;
306 off64
|= ((UQUAD
)iotd
->iotd_Req
.io_Actual
)<<32;
307 done
= ahci_sector_rw(io
, off64
, TRUE
);
310 off64
= iotd
->iotd_Req
.io_Offset
;
311 done
= ahci_sector_rw(io
, off64
, FALSE
);
314 case NSCMD_TD_READ64
:
315 off64
= iotd
->iotd_Req
.io_Offset
;
316 off64
|= ((UQUAD
)iotd
->iotd_Req
.io_Actual
)<<32;
317 done
= ahci_sector_rw(io
, off64
, FALSE
);
320 if (sizeof(struct SCSICmd
) != len
)
322 if (ap
->ap_type
== ATA_PORT_T_DISK
)
323 done
= ahci_scsi_disk_io(io
, data
);
324 else if (ap
->ap_type
== ATA_PORT_T_ATAPI
)
325 done
= ahci_scsi_atapi_io(io
, data
);
329 case TD_ADDCHANGEINT
:
330 if (io
->io_Flags
& IOF_QUICK
)
333 case TD_REMCHANGEINT
:
334 if (io
->io_Flags
& IOF_QUICK
)
339 // FIXME: Implemennt cache invalidate
343 // FIXME: Implement cache flush
347 bug("ahci.device %d: Unknown IO command %d\n", unit
->sim_Unit
, io
->io_Command
);
349 io
->io_Error
= IOERR_NOCMD
;
353 D(bug("[AHCI%02ld] IO %p Fault, io_Flags = %d, io_Command = %d, IOERR_BADLENGTH (len = %d)\n", unit
->sim_Unit
, io
, io
->io_Flags
, io
->io_Command
, len
));
354 io
->io_Error
= IOERR_BADLENGTH
;
358 io
->io_Error
= IOERR_BADADDRESS
;
363 /* The IO is finished, so no need to keep it around anymore */
365 ObtainSemaphore(&unit
->sim_Lock
);
366 Remove(&io
->io_Message
.mn_Node
);
367 ReleaseSemaphore(&unit
->sim_Lock
);
369 io
->io_Flags
&= ~IOF_QUICK
;
372 /* Need a reply now? */
373 if (done
&& !(io
->io_Flags
& IOF_QUICK
))
374 ReplyMsg(&io
->io_Message
);
377 D(bug("[AHCI%02ld] IO %p Quick, io_Flags = %d, io_Comand = %d, io_Error = %d\n", unit
->sim_Unit
, io
, io
->io_Flags
, io
->io_Command
, io
->io_Error
));
382 AROS_LH1(LONG
, AbortIO
,
383 AROS_LHA(struct IORequest
*, io
, A1
),
384 LIBBASETYPEPTR
, LIBBASE
, 6, ahci
)
388 /* Aborting IOs is not (yet) supported */
395 /* vim: set ts=8 sts=4 et : */