2 Copyright © 2004-2011, The AROS Development Team. All rights reserved
9 /* Maintainer: Jason S. McMullan <jason.mcmullan@gmail.com>
14 #include <aros/debug.h>
15 #include <aros/atomic.h>
16 #include <aros/symbolsets.h>
17 #include <exec/exec.h>
18 #include <exec/resident.h>
19 #include <exec/tasks.h>
20 #include <exec/memory.h>
21 #include <exec/nodes.h>
22 #include <utility/utility.h>
23 #include <libraries/expansion.h>
24 #include <libraries/configvars.h>
25 #include <devices/trackdisk.h>
26 #include <devices/newstyle.h>
28 #include <dos/dosextens.h>
29 #include <dos/filehandler.h>
31 #include <proto/exec.h>
32 #include <proto/timer.h>
33 #include <proto/bootloader.h>
34 #include <proto/expansion.h>
35 #include <proto/oop.h>
42 #include "ahci_intern.h"
43 #include "ahci_scsi.h"
46 #include LC_LIBDEFS_FILE
48 /* Translate to a SCSI command, since the
49 * backend will make that work on both ATAPI
52 static BOOL
ahci_sector_rw(struct IORequest
*io
, UQUAD off64
, BOOL is_write
)
54 struct IOExtTD
*iotd
= (struct IOExtTD
*)io
;
55 struct cam_sim
*unit
= (struct cam_sim
*)io
->io_Unit
;
56 struct ahci_port
*ap
= unit
->sim_Port
;
57 struct ata_port
*at
= ap
->ap_ata
[0];
58 APTR data
= iotd
->iotd_Req
.io_Data
;
59 ULONG len
= iotd
->iotd_Req
.io_Length
;
60 const ULONG bmask
= at
->at_identify
.sector_size
- 1;
62 /* It's safe to allocate these on the stack, since they
63 * will never be referenced once the ahci_scsi_*_io()
66 struct SCSICmd scsi
= {};
67 union scsi_cdb cdb
= {};
69 if (ap
->ap_type
!= ATA_PORT_T_DISK
&&
70 ap
->ap_type
!= ATA_PORT_T_ATAPI
) {
71 io
->io_Error
= TDERR_DiskChanged
;
75 if ((off64
& bmask
) || bmask
== 0 || data
== NULL
) {
76 io
->io_Error
= IOERR_BADADDRESS
;
79 if ((len
& bmask
) || len
== 0) {
80 io
->io_Error
= IOERR_BADLENGTH
;
86 IOStdReq(io
)->io_Actual
= 0;
90 scsi
.scsi_Data
= data
;
91 scsi
.scsi_Length
= len
;
92 scsi
.scsi_Flags
= is_write
? SCSIF_WRITE
: SCSIF_READ
;
94 /* Make in units of sector size */
95 len
/= at
->at_identify
.sector_size
;
96 off64
/= at
->at_identify
.sector_size
;
98 /* Set up the CDB, based on what the transfer size is */
99 scsi
.scsi_Command
= (APTR
)&cdb
;
101 if (off64
< (1 << 21) && len
< (1 << 8)) {
102 cdb
.rw_6
.opcode
= is_write
? SCSI_DA_WRITE_6
: SCSI_DA_READ_6
;
103 cdb
.rw_6
.addr
[0] = (off64
>> 16) & 0x1f;
104 cdb
.rw_6
.addr
[1] = (off64
>> 8) & 0xff;
105 cdb
.rw_6
.addr
[2] = (off64
>> 0) & 0xff;
106 cdb
.rw_6
.length
= len
;
107 scsi
.scsi_CmdLength
= sizeof(cdb
.rw_6
);
108 } else if (off64
< (1ULL << 32) && len
< (1 << 16)) {
109 cdb
.rw_10
.opcode
= is_write
? SCSI_DA_WRITE_10
: SCSI_DA_READ_10
;
110 cdb
.rw_10
.addr
[0] = (off64
>> 24) & 0xff;
111 cdb
.rw_10
.addr
[1] = (off64
>> 16) & 0xff;
112 cdb
.rw_10
.addr
[2] = (off64
>> 8) & 0xff;
113 cdb
.rw_10
.addr
[3] = (off64
>> 0) & 0xff;
114 cdb
.rw_10
.length
[0] = (len
>> 8) & 0xff;
115 cdb
.rw_10
.length
[1] = (len
>> 0) & 0xff;
116 scsi
.scsi_CmdLength
= sizeof(cdb
.rw_10
);
117 } else if (off64
< (1ULL << 32)) {
118 cdb
.rw_12
.opcode
= is_write
? SCSI_DA_WRITE_12
: SCSI_DA_READ_12
;
119 cdb
.rw_12
.addr
[0] = (off64
>> 24) & 0xff;
120 cdb
.rw_12
.addr
[1] = (off64
>> 16) & 0xff;
121 cdb
.rw_12
.addr
[2] = (off64
>> 8) & 0xff;
122 cdb
.rw_12
.addr
[3] = (off64
>> 0) & 0xff;
123 cdb
.rw_12
.length
[0] = (len
>> 24) & 0xff;
124 cdb
.rw_12
.length
[1] = (len
>> 16) & 0xff;
125 cdb
.rw_12
.length
[2] = (len
>> 8) & 0xff;
126 cdb
.rw_12
.length
[3] = (len
>> 0) & 0xff;
127 scsi
.scsi_CmdLength
= sizeof(cdb
.rw_12
);
129 cdb
.rw_16
.opcode
= is_write
? SCSI_DA_WRITE_16
: SCSI_DA_READ_16
;
130 cdb
.rw_16
.addr
[0] = (off64
>> 56) & 0xff;
131 cdb
.rw_16
.addr
[1] = (off64
>> 48) & 0xff;
132 cdb
.rw_16
.addr
[2] = (off64
>> 40) & 0xff;
133 cdb
.rw_16
.addr
[3] = (off64
>> 32) & 0xff;
134 cdb
.rw_16
.addr
[4] = (off64
>> 24) & 0xff;
135 cdb
.rw_16
.addr
[5] = (off64
>> 16) & 0xff;
136 cdb
.rw_16
.addr
[6] = (off64
>> 8) & 0xff;
137 cdb
.rw_16
.addr
[7] = (off64
>> 0) & 0xff;
138 cdb
.rw_16
.length
[0] = (len
>> 24) & 0xff;
139 cdb
.rw_16
.length
[1] = (len
>> 16) & 0xff;
140 cdb
.rw_16
.length
[2] = (len
>> 8) & 0xff;
141 cdb
.rw_16
.length
[3] = (len
>> 0) & 0xff;
142 scsi
.scsi_CmdLength
= sizeof(cdb
.rw_16
);
145 if (ap
->ap_type
== ATA_PORT_T_DISK
)
146 done
= ahci_scsi_disk_io(io
, &scsi
);
147 else if (ap
->ap_type
== ATA_PORT_T_ATAPI
)
148 done
= ahci_scsi_atapi_io(io
, &scsi
);
150 io
->io_Error
= IOERR_NOCMD
;
156 Try to do IO commands. All commands which require talking with ahci devices
157 will be handled slow, that is they will be passed to bus task which will
158 execute them as soon as hardware will be free.
160 AROS_LH1(void, BeginIO
,
161 AROS_LHA(struct IORequest
*, io
, A1
),
162 LIBBASETYPEPTR
, LIBBASE
, 5, ahci
)
166 const UWORD NSDSupported
[] = {
183 struct IOExtTD
*iotd
= (struct IOExtTD
*)io
;
184 struct cam_sim
*unit
= (struct cam_sim
*)io
->io_Unit
;
185 struct ahci_port
*ap
= unit
->sim_Port
;
186 struct ata_port
*at
= ap
->ap_ata
[0];
187 APTR data
= iotd
->iotd_Req
.io_Data
;
188 ULONG len
= iotd
->iotd_Req
.io_Length
;
190 struct DriveGeometry
*geom
;
191 struct NSDeviceQueryResult
*nsqr
;
194 io
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
196 D(bug("[AHCI%02ld] BeginIO: Start, io_Flags = %d, io_Command = %d\n", 0, io
->io_Flags
, io
->io_Command
));
198 ObtainSemaphore(&unit
->sim_Lock
);
200 switch (io
->io_Command
) {
201 case NSCMD_DEVICEQUERY
:
202 if (len
< sizeof(*nsqr
))
206 nsqr
->DevQueryFormat
= 0;
207 nsqr
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
208 nsqr
->DeviceType
= NSDEVTYPE_TRACKDISK
;
209 nsqr
->DeviceSubType
= 0;
210 nsqr
->SupportedCommands
= (UWORD
*)NSDSupported
;
211 IOStdReq(io
)->io_Actual
= sizeof(*nsqr
);
217 IOStdReq(io
)->io_Actual
= (ap
->ap_type
== ATA_PORT_T_DISK
) ? 0 : -1;
222 IOStdReq(io
)->io_Actual
= (ap
->ap_type
== ATA_PORT_T_DISK
|| ap
->ap_type
== ATA_PORT_T_ATAPI
) ? 0 : 1;
225 case TD_GETDRIVETYPE
:
226 IOStdReq(io
)->io_Actual
= DRIVE_NEWSTYLE
;
230 if (len
< sizeof(*geom
))
233 if (ap
->ap_type
!= ATA_PORT_T_DISK
&& ap
->ap_type
!= ATA_PORT_T_ATAPI
)
237 memset(geom
, 0, len
);
238 if (ap
->ap_type
== ATA_PORT_T_DISK
) {
239 geom
->dg_SectorSize
= at
->at_identify
.sector_size
;
240 geom
->dg_TotalSectors
= 0;
241 geom
->dg_Cylinders
= at
->at_identify
.ncyls
;
242 geom
->dg_CylSectors
= at
->at_identify
.nsectors
* at
->at_identify
.nheads
;
243 geom
->dg_Heads
= at
->at_identify
.nheads
;
244 geom
->dg_TrackSectors
= at
->at_identify
.nsectors
;
246 geom
->dg_BufMemType
= MEMF_PUBLIC
;
247 geom
->dg_DeviceType
= (ap
->ap_type
== ATA_PORT_T_ATAPI
) ? DG_CDROM
: DG_DIRECT_ACCESS
;
248 geom
->dg_Flags
= (at
->at_identify
.config
& (1 << 7)) ? DGF_REMOVABLE
: 0;
249 IOStdReq(io
)->io_Actual
= sizeof(*geom
);
254 if (len
& (at
->at_identify
.nsectors
* at
->at_identify
.sector_size
- 1))
256 off64
= iotd
->iotd_Req
.io_Offset
;
257 if (off64
& (at
->at_identify
.nsectors
* at
->at_identify
.sector_size
- 1))
259 done
= ahci_sector_rw(io
, off64
, TRUE
);
262 off64
= iotd
->iotd_Req
.io_Offset
;
263 done
= ahci_sector_rw(io
, off64
, TRUE
);
266 case NSCMD_TD_WRITE64
:
267 off64
= iotd
->iotd_Req
.io_Offset
;
268 off64
|= ((UQUAD
)iotd
->iotd_Req
.io_Actual
)<<32;
269 done
= ahci_sector_rw(io
, off64
, TRUE
);
272 off64
= iotd
->iotd_Req
.io_Offset
;
273 done
= ahci_sector_rw(io
, off64
, FALSE
);
276 case NSCMD_TD_READ64
:
277 off64
= iotd
->iotd_Req
.io_Offset
;
278 off64
|= ((UQUAD
)iotd
->iotd_Req
.io_Actual
)<<32;
279 done
= ahci_sector_rw(io
, off64
, FALSE
);
282 if (sizeof(struct SCSICmd
) != len
)
284 if (ap
->ap_type
== ATA_PORT_T_DISK
)
285 done
= ahci_scsi_disk_io(io
, data
);
286 else if (ap
->ap_type
== ATA_PORT_T_ATAPI
)
287 done
= ahci_scsi_atapi_io(io
, data
);
291 case TD_ADDCHANGEINT
:
292 if (io
->io_Flags
& IOF_QUICK
)
294 AddHead((struct List
*)&unit
->sim_ChangeInts
, (struct Node
*)io
);
297 case TD_REMCHANGEINT
:
298 if (io
->io_Flags
& IOF_QUICK
)
300 ahci_os_lock_port(ap
);
301 Remove((struct Node
*)io
);
302 ahci_os_unlock_port(ap
);
307 // FIXME: Implement these
312 bug("ahci.device %d: Unknown IO command %d\n", unit
->sim_Unit
, io
->io_Command
);
314 io
->io_Error
= IOERR_NOCMD
;
318 io
->io_Error
= IOERR_BADLENGTH
;
322 io
->io_Error
= IOERR_BADADDRESS
;
327 ReleaseSemaphore(&unit
->sim_Lock
);
329 if (done
|| (io
->io_Flags
& IOF_QUICK
))
330 ReplyMsg(&io
->io_Message
);
332 D(bug("[AHCI%02ld] BeginIO: Done, io_Flags = %d, io_Error = %d\n", unit
->sim_Unit
, io
->io_Flags
, io
->io_Error
));
336 AROS_LH1(LONG
, AbortIO
,
337 AROS_LHA(struct IORequest
*, io
, A1
),
338 LIBBASETYPEPTR
, LIBBASE
, 6, ahci
)
342 /* Cannot Abort IO */
349 /* vim: set ts=8 sts=4 et : */