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