xref: /haiku/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp (revision cda5b8808fd0262f0fac472f6cfa809f846a83cf)
1 /*
2  * Copyright 2007, Marcus Overhagen. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "ahci_port.h"
7 #include "ahci_controller.h"
8 #include "util.h"
9 #include "ata_cmds.h"
10 #include "scsi_cmds.h"
11 #include "sata_request.h"
12 
13 #include <KernelExport.h>
14 #include <ByteOrder.h>
15 #include <new>
16 #include <stdio.h>
17 #include <string.h>
18 
19 #define TRACE(a...) dprintf("\33[34mahci:\33[0m " a)
20 //#define FLOW(a...)	dprintf("ahci: " a)
21 //#define RWTRACE(a...) dprintf("\33[34mahci:\33[0m " a)
22 #define FLOW(a...)
23 #define RWTRACE(a...)
24 
25 
26 AHCIPort::AHCIPort(AHCIController *controller, int index)
27 	: fIndex(index)
28 	, fRegs(&controller->fRegs->port[index])
29 	, fArea(-1)
30 	, fSpinlock(0)
31 	, fCommandsActive(0)
32 	, fRequestSem(-1)
33 	, fResponseSem(-1)
34 	, fDevicePresent(false)
35 	, fUse48BitCommands(false)
36 	, fSectorSize(0)
37 	, fSectorCount(0)
38 {
39 	fRequestSem = create_sem(1, "ahci request");
40 	fResponseSem = create_sem(0, "ahci response");
41 }
42 
43 
44 AHCIPort::~AHCIPort()
45 {
46 	delete_sem(fRequestSem);
47 	delete_sem(fResponseSem);
48 }
49 
50 
51 status_t
52 AHCIPort::Init1()
53 {
54 	TRACE("AHCIPort::Init1 port %d\n", fIndex);
55 
56 	size_t size = sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT + sizeof(fis) + sizeof(command_table) + sizeof(prd) * PRD_TABLE_ENTRY_COUNT;
57 
58 	char *virtAddr;
59 	char *physAddr;
60 
61 	fArea = alloc_mem((void **)&virtAddr, (void **)&physAddr, size, 0, "some AHCI port");
62 	if (fArea < B_OK) {
63 		TRACE("failed allocating memory for port %d\n", fIndex);
64 		return fArea;
65 	}
66 	memset(virtAddr, 0, size);
67 
68 	fCommandList = (command_list_entry *)virtAddr;
69 	virtAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT;
70 	fFIS = (fis *)virtAddr;
71 	virtAddr += sizeof(fis);
72 	fCommandTable = (command_table *)virtAddr;
73 	virtAddr += sizeof(command_table);
74 	fPRDTable = (prd *)virtAddr;
75 
76 	fRegs->clb  = LO32(physAddr);
77 	fRegs->clbu = HI32(physAddr);
78 	physAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT;
79 	fRegs->fb   = LO32(physAddr);
80 	fRegs->fbu  = HI32(physAddr);
81 	physAddr += sizeof(fis);
82 	fCommandList[0].ctba  = LO32(physAddr);
83 	fCommandList[0].ctbau = HI32(physAddr);
84 	// prdt follows after command table
85 
86 	// disable transitions to partial or slumber state
87 	fRegs->sctl |= 0x300;
88 
89 	// clear IRQ status bits
90 	fRegs->is = fRegs->is;
91 
92 	// clear error bits
93 	fRegs->serr = fRegs->serr;
94 
95 	// power up device
96 	fRegs->cmd |= PORT_CMD_POD;
97 
98 	// spin up device
99 	fRegs->cmd |= PORT_CMD_SUD;
100 
101 	// activate link
102 	fRegs->cmd = (fRegs->cmd & ~PORT_CMD_ICC_MASK) | PORT_CMD_ICC_ACTIVE;
103 
104 	// enable FIS receive
105 	fRegs->cmd |= PORT_CMD_FER;
106 
107 	FlushPostedWrites();
108 
109 	return B_OK;
110 }
111 
112 
113 // called with global interrupts enabled
114 status_t
115 AHCIPort::Init2()
116 {
117 	TRACE("AHCIPort::Init2 port %d\n", fIndex);
118 
119 	// start DMA engine
120 	fRegs->cmd |= PORT_CMD_ST;
121 
122 	// enable interrupts
123 	fRegs->ie = PORT_INT_MASK;
124 
125 	FlushPostedWrites();
126 
127 	ResetDevice();
128 	PostResetDevice();
129 
130 	TRACE("ie   0x%08lx\n", fRegs->ie);
131 	TRACE("is   0x%08lx\n", fRegs->is);
132 	TRACE("cmd  0x%08lx\n", fRegs->cmd);
133 	TRACE("ssts 0x%08lx\n", fRegs->ssts);
134 	TRACE("sctl 0x%08lx\n", fRegs->sctl);
135 	TRACE("serr 0x%08lx\n", fRegs->serr);
136 	TRACE("sact 0x%08lx\n", fRegs->sact);
137 	TRACE("tfd  0x%08lx\n", fRegs->tfd);
138 
139 	fDevicePresent = (fRegs->ssts & 0xf) == 0x3;
140 
141 	return B_OK;
142 }
143 
144 
145 void
146 AHCIPort::Uninit()
147 {
148 	TRACE("AHCIPort::Uninit port %d\n", fIndex);
149 
150 	// disable FIS receive
151 	fRegs->cmd &= ~PORT_CMD_FER;
152 
153 	// wait for receive completition, up to 500ms
154 	if (wait_until_clear(&fRegs->cmd, PORT_CMD_FR, 500000) < B_OK) {
155 		TRACE("AHCIPort::Uninit port %d error FIS rx still running\n", fIndex);
156 	}
157 
158 	// stop DMA engine
159 	fRegs->cmd &= ~PORT_CMD_ST;
160 
161 	// wait for DMA completition
162 	if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
163 		TRACE("AHCIPort::Uninit port %d error DMA engine still running\n", fIndex);
164 	}
165 
166 	// disable interrupts
167 	fRegs->ie = 0;
168 
169 	// clear pending interrupts
170 	fRegs->is = fRegs->is;
171 
172 	// invalidate DMA addresses
173 	fRegs->clb  = 0;
174 	fRegs->clbu = 0;
175 	fRegs->fb   = 0;
176 	fRegs->fbu  = 0;
177 
178 	delete_area(fArea);
179 }
180 
181 
182 status_t
183 AHCIPort::ResetDevice()
184 {
185 	TRACE("AHCIPort::ResetDevice port %d\n", fIndex);
186 
187 	// stop DMA engine
188 	fRegs->cmd &= ~PORT_CMD_ST;
189 	FlushPostedWrites();
190 
191 	if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
192 		TRACE("AHCIPort::ResetDevice port %d error DMA engine doesn't stop\n", fIndex);
193 	}
194 
195 	// perform a hard reset
196 	fRegs->sctl = (fRegs->sctl & ~0xf) | 1;
197 	FlushPostedWrites();
198 	spin(1100);
199 	fRegs->sctl &= ~0xf;
200 	FlushPostedWrites();
201 
202 	if (wait_until_set(&fRegs->ssts, 0x1, 100000) < B_OK) {
203 		TRACE("AHCIPort::ResetDevice port %d no device detected\n", fIndex);
204 	}
205 
206 	// clear error bits
207 	fRegs->serr = fRegs->serr;
208 	FlushPostedWrites();
209 
210 	if (fRegs->ssts & 1) {
211 		if (wait_until_set(&fRegs->ssts, 0x3, 500000) < B_OK) {
212 			TRACE("AHCIPort::ResetDevice port %d device present but no phy communication\n", fIndex);
213 		}
214 	}
215 
216 	// clear error bits
217 	fRegs->serr = fRegs->serr;
218 	FlushPostedWrites();
219 
220 	// start DMA engine
221 	fRegs->cmd |= PORT_CMD_ST;
222 	FlushPostedWrites();
223 
224 	return B_OK;
225 }
226 
227 
228 status_t
229 AHCIPort::PostResetDevice()
230 {
231 	TRACE("AHCIPort::PostResetDevice port %d\n", fIndex);
232 
233 	if ((fRegs->ssts & 0xf) != 0x3 || (fRegs->tfd & 0xff) == 0x7f) {
234 		TRACE("AHCIPort::PostResetDevice port %d: no device\n", fIndex);
235 		return B_OK;
236 	}
237 
238 	if ((fRegs->tfd & 0xff) == 0xff)
239 		snooze(200000);
240 
241 	if ((fRegs->tfd & 0xff) == 0xff) {
242 		TRACE("AHCIPort::PostResetDevice port %d: invalid task file status 0xff\n", fIndex);
243 		return B_ERROR;
244 	}
245 
246 	wait_until_clear(&fRegs->tfd, ATA_BSY, 31000000);
247 
248 	if (fRegs->sig == 0xeb140101)
249 		fRegs->cmd |= PORT_CMD_ATAPI;
250 	else
251 		fRegs->cmd &= ~PORT_CMD_ATAPI;
252 	FlushPostedWrites();
253 
254 	TRACE("device signature 0x%08lx (%s)\n", fRegs->sig,
255 		(fRegs->sig == 0xeb140101) ? "ATAPI" : (fRegs->sig == 0x00000101) ? "ATA" : "unknown");
256 
257 	return B_OK;
258 }
259 
260 
261 void
262 AHCIPort::DumpD2HFis()
263 {
264 	TRACE("D2H FIS:\n");
265 	TRACE("  DW0  %02x %02x %02x %02x\n", fFIS->rfis[3], fFIS->rfis[2], fFIS->rfis[1], fFIS->rfis[0]);
266 	TRACE("  DW1  %02x %02x %02x %02x\n", fFIS->rfis[7], fFIS->rfis[6], fFIS->rfis[5], fFIS->rfis[4]);
267 	TRACE("  DW2  %02x %02x %02x %02x\n", fFIS->rfis[11], fFIS->rfis[10], fFIS->rfis[9], fFIS->rfis[8]);
268 	TRACE("  DW3  %02x %02x %02x %02x\n", fFIS->rfis[15], fFIS->rfis[14], fFIS->rfis[13], fFIS->rfis[12]);
269 	TRACE("  DW4  %02x %02x %02x %02x\n", fFIS->rfis[19], fFIS->rfis[18], fFIS->rfis[17], fFIS->rfis[16]);
270 }
271 
272 
273 void
274 AHCIPort::Interrupt()
275 {
276 	uint32 is = fRegs->is;
277 	uint32 ci = fRegs->ci;
278 	fRegs->is = is; // clear interrupts
279 
280 	RWTRACE("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
281 
282 	if (is & PORT_INT_ERROR)
283 		TRACE("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
284 
285 	if (is & PORT_INT_FATAL)
286 		panic("ahci fatal error, is 0x%08lx", is);
287 
288 	int release = 0;
289 
290 	acquire_spinlock(&fSpinlock);
291 	if ((fCommandsActive & 1) && !(ci & 1)) {
292 		release = 1;
293 		fCommandsActive &= ~1;
294 	}
295 	release_spinlock(&fSpinlock);
296 
297 	if (release)
298 		release_sem_etc(fResponseSem, 1, B_RELEASE_IF_WAITING_ONLY | B_DO_NOT_RESCHEDULE);
299 }
300 
301 
302 status_t
303 AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize)
304 {
305 	int peMax = prdMax + 1;
306 	physical_entry pe[peMax];
307 	if (get_memory_map(data, dataSize, pe, peMax ) < B_OK) {
308 		TRACE("AHCIPort::FillPrdTable get_memory_map failed\n");
309 		return B_ERROR;
310 	}
311 	int peUsed;
312 	for (peUsed = 0; pe[peUsed].size; peUsed++)
313 		;
314 	return FillPrdTable(prdTable, prdCount, prdMax, pe, peUsed, dataSize);
315 }
316 
317 
318 status_t
319 AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize)
320 {
321 	*prdCount = 0;
322 	while (sgCount > 0 && dataSize > 0) {
323 		size_t size = min_c(sgTable->size, dataSize);
324 		void *address = sgTable->address;
325 		FLOW("FillPrdTable: sg-entry addr %p, size %lu\n", address, size);
326 		if ((uint32)address & 1) {
327 			TRACE("AHCIPort::FillPrdTable: data alignment error\n");
328 			return B_ERROR;
329 		}
330 		dataSize -= size;
331 		while (size > 0) {
332 			size_t bytes = min_c(size, PRD_MAX_DATA_LENGTH);
333 			if (*prdCount == prdMax) {
334 				TRACE("AHCIPort::FillPrdTable: prd table exhausted\n");
335 				return B_ERROR;
336 			}
337 			FLOW("FillPrdTable: prd-entry %u, addr %p, size %lu\n", *prdCount, address, bytes);
338 			prdTable->dba  = LO32(address);
339 			prdTable->dbau = HI32(address);
340 			prdTable->res  = 0;
341 			prdTable->dbc  = bytes - 1;
342 			*prdCount += 1;
343 			prdTable++;
344 			address = (char *)address + bytes;
345 			size -= bytes;
346 		}
347 		sgTable++;
348 		sgCount--;
349 	}
350 	if (*prdCount == 0) {
351 		TRACE("AHCIPort::FillPrdTable: count is 0\n");
352 		return B_ERROR;
353 	}
354 	if (dataSize > 0) {
355 		TRACE("AHCIPort::FillPrdTable: sg table %ld bytes too small\n", dataSize);
356 		return B_ERROR;
357 	}
358 	return B_OK;
359 }
360 
361 
362 void
363 AHCIPort::StartTransfer()
364 {
365 	acquire_sem(fRequestSem);
366 }
367 
368 
369 status_t
370 AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout)
371 {
372 	status_t result = B_OK;
373 	if (acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout) < B_OK) {
374 		fCommandsActive &= ~1;
375 		result = B_TIMED_OUT;
376 	} else {
377 		*tfd = fRegs->tfd;
378 	}
379 	return result;
380 }
381 
382 
383 void
384 AHCIPort::FinishTransfer()
385 {
386 	release_sem(fRequestSem);
387 }
388 
389 
390 void
391 AHCIPort::ScsiTestUnitReady(scsi_ccb *request)
392 {
393 	TRACE("AHCIPort::ScsiTestUnitReady port %d\n", fIndex);
394 	request->subsys_status = SCSI_REQ_CMP;
395 	gSCSI->finished(request, 1);
396 }
397 
398 
399 void
400 AHCIPort::ScsiInquiry(scsi_ccb *request)
401 {
402 	TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex);
403 
404 	scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)request->cdb;
405 	scsi_res_inquiry scsiData;
406 	ata_res_identify_device	ataData;
407 
408 	ASSERT(sizeof(ataData) == 512);
409 
410 	if (cmd->evpd || cmd->page_code || request->data_length < sizeof(scsiData)) {
411 		TRACE("invalid request\n");
412 		request->subsys_status = SCSI_REQ_ABORTED;
413 		gSCSI->finished(request, 1);
414 		return;
415 	}
416 
417 	sata_request sreq;
418 	sreq.set_data(&ataData, sizeof(ataData));
419 	sreq.set_ata_cmd(0xec); // Identify Device
420 	ExecuteSataRequest(&sreq);
421 	sreq.wait_for_completition();
422 
423 	if (sreq.completition_status() & ATA_ERR) {
424 		TRACE("identify device failed\n");
425 		request->subsys_status = SCSI_REQ_CMP_ERR;
426 		gSCSI->finished(request, 1);
427 		return;
428 	}
429 
430 /*
431 	uint8 *data = (uint8*) &ataData;
432 	for (int i = 0; i < 512; i += 8) {
433 		TRACE("  %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]);
434 	}
435 */
436 
437 	scsiData.device_type = scsi_dev_direct_access;
438 	scsiData.device_qualifier = scsi_periph_qual_connected;
439 	scsiData.device_type_modifier = 0;
440 	scsiData.removable_medium = false;
441 	scsiData.ansi_version = 2;
442 	scsiData.ecma_version = 0;
443 	scsiData.iso_version = 0;
444 	scsiData.response_data_format = 2;
445 	scsiData.term_iop = false;
446 	scsiData.additional_length = sizeof(scsiData) - 4;
447 	scsiData.soft_reset = false;
448 	scsiData.cmd_queue = false;
449 	scsiData.linked = false;
450 	scsiData.sync = false;
451 	scsiData.write_bus16 = true;
452 	scsiData.write_bus32 = false;
453 	scsiData.relative_address = false;
454 	memcpy(scsiData.vendor_ident, ataData.model_number, sizeof(scsiData.vendor_ident));
455 	memcpy(scsiData.product_ident, ataData.model_number + 8, sizeof(scsiData.product_ident));
456 	memcpy(scsiData.product_rev, ataData.serial_number, sizeof(scsiData.product_rev));
457 
458 	bool lba			= (ataData.words[49] & (1 << 9)) != 0;
459 	bool lba48			= (ataData.words[83] & (1 << 10)) != 0;
460 	uint32 sectors		= *(uint32*)&ataData.words[60];
461 	uint64 sectors48	= *(uint64*)&ataData.words[100];
462 	fUse48BitCommands   = lba && lba48;
463 	fSectorSize			= 512;
464 	fSectorCount		= !(lba || sectors) ? 0 : lba48 ? sectors48 : sectors;
465 
466 #if 0
467 	if (fSectorCount < 0x0fffffff) {
468 		TRACE("disabling 48 bit commands\n");
469 		fUse48BitCommands = 0;
470 	}
471 #endif
472 
473 	char modelNumber[sizeof(ataData.model_number) + 1];
474 	char serialNumber[sizeof(ataData.serial_number) + 1];
475 	char firmwareRev[sizeof(ataData.firmware_revision) + 1];
476 
477 	strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber));
478 	strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber));
479 	strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev));
480 
481 	swap_words(modelNumber, sizeof(modelNumber) - 1);
482 	swap_words(serialNumber, sizeof(serialNumber) - 1);
483 	swap_words(firmwareRev, sizeof(firmwareRev) - 1);
484 
485 	TRACE("model number:  %s\n", modelNumber);
486 	TRACE("serial number: %s\n", serialNumber);
487   	TRACE("firmware rev.: %s\n", firmwareRev);
488 	TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %lu, sectors48 %llu, size %llu\n",
489 		lba, lba48, fUse48BitCommands, sectors, sectors48, fSectorCount * fSectorSize);
490 
491 	if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, sizeof(scsiData)) < B_OK) {
492 		request->subsys_status = SCSI_DATA_RUN_ERR;
493 	} else {
494 		request->subsys_status = SCSI_REQ_CMP;
495 		request->data_resid = request->data_length - sizeof(scsiData);
496 	}
497 	gSCSI->finished(request, 1);
498 }
499 
500 
501 void
502 AHCIPort::ScsiSynchronizeCache(scsi_ccb *request)
503 {
504 	TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex);
505 
506 	sata_request *sreq = new(std::nothrow) sata_request(request);
507 	sreq->set_ata_cmd(fUse48BitCommands ? 0xea : 0xe7); // Flush Cache
508 	ExecuteSataRequest(sreq);
509 }
510 
511 
512 void
513 AHCIPort::ScsiReadCapacity(scsi_ccb *request)
514 {
515 	TRACE("AHCIPort::ScsiReadCapacity port %d\n", fIndex);
516 
517 	scsi_cmd_read_capacity *cmd = (scsi_cmd_read_capacity *)request->cdb;
518 	scsi_res_read_capacity scsiData;
519 
520 	if (cmd->pmi || cmd->lba || request->data_length < sizeof(scsiData)) {
521 		TRACE("invalid request\n");
522 		return;
523 	}
524 
525 	TRACE("SectorSize %lu, SectorCount 0x%llx\n", fSectorSize, fSectorCount);
526 
527 	if (fSectorCount > 0xffffffff)
528 		panic("ahci: SCSI emulation doesn't support harddisks larger than 2TB");
529 
530 	scsiData.block_size = B_HOST_TO_BENDIAN_INT32(fSectorSize);
531 	scsiData.lba = B_HOST_TO_BENDIAN_INT32(fSectorCount - 1);
532 
533 	if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, sizeof(scsiData)) < B_OK) {
534 		request->subsys_status = SCSI_DATA_RUN_ERR;
535 	} else {
536 		request->subsys_status = SCSI_REQ_CMP;
537 		request->data_resid = request->data_length - sizeof(scsiData);
538 	}
539 	gSCSI->finished(request, 1);
540 }
541 
542 
543 void
544 AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, bool isWrite)
545 {
546 	RWTRACE("ScsiReadWrite: position %llu, size %lu, isWrite %d\n", lba * 512, sectorCount * 512, isWrite);
547 
548 #if 0
549 	if (isWrite) {
550 		TRACE("write request ignored\n");
551 		request->subsys_status = SCSI_REQ_CMP;
552 		request->data_resid = 0;
553 		gSCSI->finished(request, 1);
554 		return;
555 	}
556 #endif
557 
558 	ASSERT(request->data_length == sectorCount * 512);
559 	sata_request *sreq = new(std::nothrow) sata_request(request);
560 
561 	if (fUse48BitCommands) {
562 		if (sectorCount > 65536)
563 			panic("ahci: ScsiReadWrite length too large, %lu sectors", sectorCount);
564 		if (lba > MAX_SECTOR_LBA_48)
565 			panic("achi: ScsiReadWrite position too large for 48-bit LBA\n");
566 		sreq->set_ata48_cmd(isWrite ? 0x35 : 0x25, lba, sectorCount);
567 	} else {
568 		if (sectorCount > 256)
569 			panic("ahci: ScsiReadWrite length too large, %lu sectors", sectorCount);
570 		if (lba > MAX_SECTOR_LBA_28)
571 			panic("achi: ScsiReadWrite position too large for normal LBA\n");
572 		sreq->set_ata28_cmd(isWrite ? 0xca : 0xc8, lba, sectorCount);
573 	}
574 
575 	ExecuteSataRequest(sreq, isWrite);
576 }
577 
578 
579 void
580 AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite)
581 {
582 	FLOW("ExecuteAtaRequest port %d\n", fIndex);
583 
584 	StartTransfer();
585 
586 	int prdEntrys;
587 
588 	if (request->ccb())
589 		FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->ccb()->sg_list, request->ccb()->sg_count, request->ccb()->data_length);
590 	else if (request->data() && request->size())
591 		FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->data(), request->size());
592 	else
593 		prdEntrys = 0;
594 
595 	FLOW("prdEntrys %d\n", prdEntrys);
596 
597 	memcpy((char *)fCommandTable->cfis, request->fis(), 20);
598 	fCommandList->prdtl_flags_cfl = 0;
599 	fCommandList->cfl = 5; // length is 20 bytes, in DWORDS
600 	if (isWrite)
601 		fCommandList->w = 1;
602 	fCommandList->prdtl = prdEntrys;
603 	fCommandList->prdbc = 0;
604 
605 	if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 1000000) < B_OK) {
606 		TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex);
607 		FinishTransfer();
608 		request->abort();
609 		return;
610 	}
611 
612 	cpu_status cpu = disable_interrupts();
613 	acquire_spinlock(&fSpinlock);
614 	fRegs->ci = 1;
615 	FlushPostedWrites();
616 	fCommandsActive |= 1;
617 	release_spinlock(&fSpinlock);
618 	restore_interrupts(cpu);
619 
620 	int tfd;
621 	status_t status = WaitForTransfer(&tfd, 5000000);
622 
623 	FLOW("tfd %#x\n", tfd);
624 	FLOW("prdbc %ld\n", fCommandList->prdbc);
625 	FLOW("ci   0x%08lx\n", fRegs->ci);
626 	FLOW("is   0x%08lx\n", fRegs->is);
627 	FLOW("serr 0x%08lx\n", fRegs->serr);
628 
629 /*
630 	TRACE("ci   0x%08lx\n", fRegs->ci);
631 	TRACE("ie   0x%08lx\n", fRegs->ie);
632 	TRACE("is   0x%08lx\n", fRegs->is);
633 	TRACE("cmd  0x%08lx\n", fRegs->cmd);
634 	TRACE("ssts 0x%08lx\n", fRegs->ssts);
635 	TRACE("sctl 0x%08lx\n", fRegs->sctl);
636 	TRACE("serr 0x%08lx\n", fRegs->serr);
637 	TRACE("sact 0x%08lx\n", fRegs->sact);
638 	TRACE("tfd  0x%08lx\n", fRegs->tfd);
639 */
640 
641 	size_t bytesTransfered = fCommandList->prdbc;
642 
643 	FinishTransfer();
644 
645 	if (status < B_OK) {
646 		TRACE("ExecuteAtaRequest port %d: device transfer timeout\n", fIndex);
647 		request->abort();
648 	} else
649 		request->finish(tfd, bytesTransfered);
650 }
651 
652 
653 void
654 AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
655 {
656 
657 //	TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
658 
659 	if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) {
660 		panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");
661 		return;
662 	}
663 
664 	if (!fDevicePresent) {
665 		TRACE("no device present on port %d\n", fIndex);
666 		request->subsys_status = SCSI_DEV_NOT_THERE;
667 		gSCSI->finished(request, 1);
668 		return;
669 	}
670 
671 	request->subsys_status = SCSI_REQ_CMP;
672 
673 	switch (request->cdb[0]) {
674 		case SCSI_OP_TEST_UNIT_READY:
675 			ScsiTestUnitReady(request);
676 			break;
677 		case SCSI_OP_INQUIRY:
678 			ScsiInquiry(request);
679 			break;
680 		case SCSI_OP_READ_CAPACITY:
681 			ScsiReadCapacity(request);
682 			break;
683 		case SCSI_OP_SYNCHRONIZE_CACHE:
684 			ScsiSynchronizeCache(request);
685 			break;
686 		case SCSI_OP_READ_6:
687 		case SCSI_OP_WRITE_6:
688 		{
689 			scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb;
690 			uint32 position = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba;
691 			size_t length = cmd->length != 0 ? cmd->length : 256;
692 			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6;
693 			ScsiReadWrite(request, position, length, isWrite);
694 			break;
695 		}
696 		case SCSI_OP_READ_10:
697 		case SCSI_OP_WRITE_10:
698 		{
699 			scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb;
700 			uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
701 			size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length);
702 			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10;
703 			if (length) {
704 				ScsiReadWrite(request, position, length, isWrite);
705 			} else {
706 				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without data!\n");
707 				request->subsys_status = SCSI_REQ_INVALID;
708 				gSCSI->finished(request, 1);
709 			}
710 			break;
711 		}
712 		case SCSI_OP_READ_12:
713 		case SCSI_OP_WRITE_12:
714 		{
715 			scsi_cmd_rw_12 *cmd = (scsi_cmd_rw_12 *)request->cdb;
716 			uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
717 			size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
718 			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12;
719 			if (length) {
720 				ScsiReadWrite(request, position, length, isWrite);
721 			} else {
722 				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without data!\n");
723 				request->subsys_status = SCSI_REQ_INVALID;
724 				gSCSI->finished(request, 1);
725 			}
726 			break;
727 		}
728 		default:
729 			TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request opcode 0x%02x\n", fIndex, request->cdb[0]);
730 			request->subsys_status = SCSI_REQ_ABORTED;
731 			gSCSI->finished(request, 1);
732 	}
733 }
734 
735 
736 uchar
737 AHCIPort::ScsiAbortRequest(scsi_ccb *request)
738 {
739 
740 	return SCSI_REQ_CMP;
741 }
742 
743 
744 uchar
745 AHCIPort::ScsiTerminateRequest(scsi_ccb *request)
746 {
747 	return SCSI_REQ_CMP;
748 }
749 
750 
751 uchar
752 AHCIPort::ScsiResetDevice()
753 {
754 	return SCSI_REQ_CMP;
755 }
756 
757 
758 void
759 AHCIPort::ScsiGetRestrictions(bool *isATAPI, bool *noAutoSense, uint32 *maxBlocks)
760 {
761 	*isATAPI = !!(fRegs->cmd & PORT_CMD_ATAPI);
762 	*noAutoSense = false;
763 	*maxBlocks = fUse48BitCommands ? 65536 : 256;
764 	TRACE("AHCIPort::ScsiGetRestrictions port %d: isATAPI %d, noAutoSense %d, maxBlocks %lu\n",
765 		fIndex, *isATAPI, *noAutoSense, *maxBlocks);
766 }
767