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