ahci: Add stub TD_ADDCHANGEINT, TD_REMCHANGEINT
[AROS.git] / rom / devs / ahci / ahci_io.c
blob9240e267179a9e003824ed840bb414e747f7c151
1 /*
2 Copyright © 2004-2011, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
9 /* Maintainer: Jason S. McMullan <jason.mcmullan@gmail.com>
12 #define DEBUG 0
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>
27 #include <dos/bptr.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>
37 #include <hidd/pci.h>
39 #include <string.h>
41 #include "ahci.h"
42 #include "ahci_intern.h"
43 #include "ahci_scsi.h"
44 #include "timer.h"
46 #include LC_LIBDEFS_FILE
48 /* Translate to a SCSI command, since the
49 * backend will make that work on both ATAPI
50 * and ATA devices.
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;
61 BOOL done = TRUE;
62 /* It's safe to allocate these on the stack, since they
63 * will never be referenced once the ahci_scsi_*_io()
64 * routine returns.
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;
72 return TRUE;
75 if ((off64 & bmask) || bmask == 0 || data == NULL) {
76 io->io_Error = IOERR_BADADDRESS;
77 return TRUE;
79 if ((len & bmask) || len == 0) {
80 io->io_Error = IOERR_BADLENGTH;
81 return TRUE;
84 if (len == 0) {
85 io->io_Error = 0;
86 IOStdReq(io)->io_Actual = 0;
87 return TRUE;
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);
128 } else {
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);
149 else
150 io->io_Error = IOERR_NOCMD;
152 return done;
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)
164 AROS_LIBFUNC_INIT
166 const UWORD NSDSupported[] = {
167 CMD_READ,
168 CMD_WRITE,
169 CMD_UPDATE,
170 TD_ADDCHANGEINT,
171 TD_CHANGESTATE,
172 TD_FORMAT,
173 TD_GETGEOMETRY,
174 TD_PROTSTATUS,
175 TD_READ64,
176 TD_REMCHANGEINT,
177 TD_WRITE64,
178 NSCMD_DEVICEQUERY,
179 NSCMD_TD_READ64,
180 NSCMD_TD_WRITE64,
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;
189 UQUAD off64;
190 struct DriveGeometry *geom;
191 struct NSDeviceQueryResult *nsqr;
192 BOOL done = FALSE;
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))
203 goto bad_length;
205 nsqr = data;
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);
212 io->io_Error = 0;
213 done = TRUE;
214 break;
215 case TD_PROTSTATUS:
216 io->io_Error = 0;
217 IOStdReq(io)->io_Actual = (ap->ap_type == ATA_PORT_T_DISK) ? 0 : -1;
218 done = TRUE;
219 break;
220 case TD_CHANGESTATE:
221 io->io_Error = 0;
222 IOStdReq(io)->io_Actual = (ap->ap_type == ATA_PORT_T_DISK || ap->ap_type == ATA_PORT_T_ATAPI) ? 0 : 1;
223 done = TRUE;
224 break;
225 case TD_GETDRIVETYPE:
226 IOStdReq(io)->io_Actual = DRIVE_NEWSTYLE;
227 done = TRUE;
228 break;
229 case TD_GETGEOMETRY:
230 if (len < sizeof(*geom))
231 goto bad_length;
233 if (ap->ap_type != ATA_PORT_T_DISK && ap->ap_type != ATA_PORT_T_ATAPI)
234 goto bad_cmd;
236 geom = data;
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);
250 io->io_Error = 0;
251 done = TRUE;
252 break;
253 case TD_FORMAT:
254 if (len & (at->at_identify.nsectors * at->at_identify.sector_size - 1))
255 goto bad_length;
256 off64 = iotd->iotd_Req.io_Offset;
257 if (off64 & (at->at_identify.nsectors * at->at_identify.sector_size - 1))
258 goto bad_address;
259 done = ahci_sector_rw(io, off64, TRUE);
260 break;
261 case CMD_WRITE:
262 off64 = iotd->iotd_Req.io_Offset;
263 done = ahci_sector_rw(io, off64, TRUE);
264 break;
265 case TD_WRITE64:
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);
270 break;
271 case CMD_READ:
272 off64 = iotd->iotd_Req.io_Offset;
273 done = ahci_sector_rw(io, off64, FALSE);
274 break;
275 case TD_READ64:
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);
280 break;
281 case HD_SCSICMD:
282 if (sizeof(struct SCSICmd) != len)
283 goto bad_length;
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);
288 else
289 goto bad_cmd;
290 break;
291 case TD_ADDCHANGEINT:
292 if (io->io_Flags & IOF_QUICK)
293 goto bad_cmd;
294 AddHead((struct List *)&unit->sim_ChangeInts, (struct Node *)io);
295 io->io_Error = 0;
296 break;
297 case TD_REMCHANGEINT:
298 if (io->io_Flags & IOF_QUICK)
299 goto bad_cmd;
300 ahci_os_lock_port(ap);
301 Remove((struct Node *)io);
302 ahci_os_unlock_port(ap);
303 io->io_Error = 0;
304 done = TRUE;
305 break;
306 case CMD_UPDATE:
307 // FIXME: Implement these
308 io->io_Error = 0;
309 done = TRUE;
310 break;
311 default:
312 bug("ahci.device %d: Unknown IO command %d\n", unit->sim_Unit, io->io_Command);
313 bad_cmd:
314 io->io_Error = IOERR_NOCMD;
315 done = TRUE;
316 break;
317 bad_length:
318 io->io_Error = IOERR_BADLENGTH;
319 done = TRUE;
320 break;
321 bad_address:
322 io->io_Error = IOERR_BADADDRESS;
323 done = TRUE;
324 break;
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));
333 AROS_LIBFUNC_EXIT
336 AROS_LH1(LONG, AbortIO,
337 AROS_LHA(struct IORequest *, io, A1),
338 LIBBASETYPEPTR, LIBBASE, 6, ahci)
340 AROS_LIBFUNC_INIT
342 /* Cannot Abort IO */
343 return 0;
345 AROS_LIBFUNC_EXIT
349 /* vim: set ts=8 sts=4 et : */