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
37AHCIPort::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
62AHCIPort::~AHCIPort()
63{
64	delete_sem(fRequestSem);
65	delete_sem(fResponseSem);
66}
67
68
69status_t
70AHCIPort::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
136status_t
137AHCIPort::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
166void
167AHCIPort::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
204void
205AHCIPort::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
239status_t
240AHCIPort::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
272status_t
273AHCIPort::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
312void
313AHCIPort::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
329void
330AHCIPort::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
355void
356AHCIPort::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\n");
402		fResetPort = true;
403		fError = true;
404	}
405	if (is & PORT_INT_IPM) {
406		TRACE("Incorrect Port Multiplier Status\n");
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
432status_t
433AHCIPort::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
449status_t
450AHCIPort::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
499void
500AHCIPort::StartTransfer()
501{
502	acquire_sem(fRequestSem);
503}
504
505
506status_t
507AHCIPort::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
530void
531AHCIPort::FinishTransfer()
532{
533	release_sem(fRequestSem);
534}
535
536
537void
538AHCIPort::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
546void
547AHCIPort::ScsiInquiry(scsi_ccb *request)
548{
549	TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex);
550
551	const scsi_cmd_inquiry *cmd = (const 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
586		? ataData.word_0.atapi.command_packet_set : scsi_dev_direct_access;
587	scsiData.device_qualifier = scsi_periph_qual_connected;
588	scsiData.device_type_modifier = 0;
589	scsiData.removable_medium = ataData.word_0.ata.removable_media_device;
590	scsiData.ansi_version = 2;
591	scsiData.ecma_version = 0;
592	scsiData.iso_version = 0;
593	scsiData.response_data_format = 2;
594	scsiData.term_iop = false;
595	scsiData.additional_length = sizeof(scsi_res_inquiry) - 4;
596	scsiData.soft_reset = false;
597	scsiData.cmd_queue = false;
598	scsiData.linked = false;
599	scsiData.sync = false;
600	scsiData.write_bus16 = true;
601	scsiData.write_bus32 = false;
602	scsiData.relative_address = false;
603
604	if (!fIsATAPI) {
605		fSectorCount = ataData.SectorCount(fUse48BitCommands, true);
606		fSectorSize = ataData.SectorSize();
607		fTrim = ataData.data_set_management_support;
608		TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %" B_PRIu32
609			", sectors48 %" B_PRIu64 ", size %" B_PRIu64 "\n",
610			ataData.dma_supported != 0, ataData.lba48_supported != 0,
611			fUse48BitCommands, ataData.lba_sector_count,
612			ataData.lba48_sector_count, fSectorCount * fSectorSize);
613	}
614
615#if 0
616	if (fSectorCount < 0x0fffffff) {
617		TRACE("disabling 48 bit commands\n");
618		fUse48BitCommands = 0;
619	}
620#endif
621
622	char modelNumber[sizeof(ataData.model_number) + 1];
623	char serialNumber[sizeof(ataData.serial_number) + 1];
624	char firmwareRev[sizeof(ataData.firmware_revision) + 1];
625
626	strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber));
627	strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber));
628	strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev));
629
630	swap_words(modelNumber, sizeof(modelNumber) - 1);
631	swap_words(serialNumber, sizeof(serialNumber) - 1);
632	swap_words(firmwareRev, sizeof(firmwareRev) - 1);
633
634	TRACE("model number: %s\n", modelNumber);
635	TRACE("serial number: %s\n", serialNumber);
636	TRACE("firmware rev.: %s\n", firmwareRev);
637	TRACE("trim support: %s\n", fTrim ? "yes" : "no");
638
639	// There's not enough space to fit all of the data in. ATA has 40 bytes for
640	// the model number, 20 for the serial number and another 8 for the
641	// firmware revision. SCSI has room for 8 for vendor ident, 16 for product
642	// ident and another 4 for product revision. We just try and fit in as much
643	// as possible of the model number into the vendor and product ident fields
644	// and put a little of the serial number into the product revision field.
645	memcpy(scsiData.vendor_ident, modelNumber, sizeof(scsiData.vendor_ident));
646	memcpy(scsiData.product_ident, modelNumber + 8,
647		sizeof(scsiData.product_ident));
648	memcpy(scsiData.product_rev, serialNumber, sizeof(scsiData.product_rev));
649
650	if (sg_memcpy(request->sg_list, request->sg_count, &scsiData,
651			sizeof(scsiData)) < B_OK) {
652		request->subsys_status = SCSI_DATA_RUN_ERR;
653	} else {
654		request->subsys_status = SCSI_REQ_CMP;
655		request->data_resid = request->data_length - sizeof(scsiData);
656	}
657	gSCSI->finished(request, 1);
658}
659
660
661void
662AHCIPort::ScsiSynchronizeCache(scsi_ccb *request)
663{
664	//TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex);
665
666	sata_request *sreq = new(std::nothrow) sata_request(request);
667	if (sreq == NULL) {
668		TRACE("out of memory when allocating sync request\n");
669		request->subsys_status = SCSI_REQ_ABORTED;
670		gSCSI->finished(request, 1);
671		return;
672	}
673
674	sreq->set_ata_cmd(fUse48BitCommands ? 0xea : 0xe7); // Flush Cache
675	ExecuteSataRequest(sreq);
676}
677
678
679void
680AHCIPort::ScsiReadCapacity(scsi_ccb *request)
681{
682	TRACE("AHCIPort::ScsiReadCapacity port %d\n", fIndex);
683
684	const scsi_cmd_read_capacity *cmd = (const scsi_cmd_read_capacity *)request->cdb;
685	scsi_res_read_capacity scsiData;
686
687	if (cmd->pmi || cmd->lba || request->data_length < sizeof(scsiData)) {
688		TRACE("invalid request\n");
689		request->subsys_status = SCSI_REQ_ABORTED;
690		gSCSI->finished(request, 1);
691		return;
692	}
693
694	TRACE("SectorSize %" B_PRIu32 ", SectorCount 0x%" B_PRIx64 "\n",
695		fSectorSize, fSectorCount);
696
697	scsiData.block_size = B_HOST_TO_BENDIAN_INT32(fSectorSize);
698
699	if (fSectorCount <= 0xffffffff)
700		scsiData.lba = B_HOST_TO_BENDIAN_INT32(fSectorCount - 1);
701	else
702		scsiData.lba = 0xffffffff;
703
704	if (sg_memcpy(request->sg_list, request->sg_count, &scsiData,
705			sizeof(scsiData)) < B_OK) {
706		request->subsys_status = SCSI_DATA_RUN_ERR;
707	} else {
708		request->subsys_status = SCSI_REQ_CMP;
709		request->data_resid = request->data_length - sizeof(scsiData);
710	}
711	gSCSI->finished(request, 1);
712}
713
714
715void
716AHCIPort::ScsiReadCapacity16(scsi_ccb *request)
717{
718	TRACE("AHCIPort::ScsiReadCapacity16 port %d\n", fIndex);
719
720	//const scsi_cmd_read_capacity_long *cmd = (const scsi_cmd_read_capacity_long *)request->cdb;
721	scsi_res_read_capacity_long scsiData;
722
723	TRACE("SectorSize %" B_PRIu32 ", SectorCount 0x%" B_PRIx64 "\n",
724		fSectorSize, fSectorCount);
725
726	scsiData.block_size = B_HOST_TO_BENDIAN_INT32(fSectorSize);
727	scsiData.lba = B_HOST_TO_BENDIAN_INT64(fSectorCount - 1);
728
729	if (sg_memcpy(request->sg_list, request->sg_count, &scsiData,
730			sizeof(scsiData)) < B_OK) {
731		request->subsys_status = SCSI_DATA_RUN_ERR;
732	} else {
733		request->subsys_status = SCSI_REQ_CMP;
734		request->data_resid = request->data_length - sizeof(scsiData);
735	}
736	gSCSI->finished(request, 1);
737}
738
739
740void
741AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount,
742	bool isWrite)
743{
744	RWTRACE("[%lld] %ld ScsiReadWrite: position %llu, size %lu, isWrite %d\n",
745		system_time(), find_thread(NULL), lba * 512, sectorCount * 512,
746		isWrite);
747
748#if 0
749	if (isWrite) {
750		TRACE("write request ignored\n");
751		request->subsys_status = SCSI_REQ_CMP;
752		request->data_resid = 0;
753		gSCSI->finished(request, 1);
754		return;
755	}
756#endif
757
758	ASSERT(request->data_length == sectorCount * 512);
759	sata_request *sreq = new(std::nothrow) sata_request(request);
760	if (sreq == NULL) {
761		TRACE("out of memory when allocating read/write request\n");
762		request->subsys_status = SCSI_REQ_ABORTED;
763		gSCSI->finished(request, 1);
764		return;
765	}
766
767	if (fUse48BitCommands) {
768		if (sectorCount > 65536) {
769			panic("ahci: ScsiReadWrite length too large, %lu sectors",
770				sectorCount);
771		}
772		if (lba > MAX_SECTOR_LBA_48)
773			panic("achi: ScsiReadWrite position too large for 48-bit LBA\n");
774		sreq->set_ata48_cmd(isWrite ? 0x35 : 0x25, lba, sectorCount);
775	} else {
776		if (sectorCount > 256) {
777			panic("ahci: ScsiReadWrite length too large, %lu sectors",
778				sectorCount);
779		}
780		if (lba > MAX_SECTOR_LBA_28)
781			panic("achi: ScsiReadWrite position too large for normal LBA\n");
782		sreq->set_ata28_cmd(isWrite ? 0xca : 0xc8, lba, sectorCount);
783	}
784
785	ExecuteSataRequest(sreq, isWrite);
786}
787
788
789void
790AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite)
791{
792	FLOW("ExecuteAtaRequest port %d\n", fIndex);
793
794	StartTransfer();
795
796	int prdEntrys;
797
798	if (request->ccb() && request->ccb()->data_length) {
799		FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT,
800			request->ccb()->sg_list, request->ccb()->sg_count,
801			request->ccb()->data_length);
802	} else if (request->data() && request->size()) {
803		FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT,
804			request->data(), request->size());
805	} else
806		prdEntrys = 0;
807
808	FLOW("prdEntrys %d\n", prdEntrys);
809
810	fCommandList->prdtl_flags_cfl = 0;
811	fCommandList->cfl = 5; // 20 bytes, length in DWORDS
812	memcpy((char *)fCommandTable->cfis, request->fis(), 20);
813
814	fTestUnitReadyActive = request->is_test_unit_ready();
815	if (request->is_atapi()) {
816		// ATAPI PACKET is a 12 or 16 byte SCSI command
817		memset((char *)fCommandTable->acmd, 0, 32);
818		memcpy((char *)fCommandTable->acmd, request->ccb()->cdb,
819			request->ccb()->cdb_length);
820		fCommandList->a = 1;
821	}
822
823	if (isWrite)
824		fCommandList->w = 1;
825	fCommandList->prdtl = prdEntrys;
826	fCommandList->prdbc = 0;
827
828	if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 1000000) < B_OK) {
829		TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex);
830		ResetPort();
831		FinishTransfer();
832		request->abort();
833		return;
834	}
835
836	cpu_status cpu = disable_interrupts();
837	acquire_spinlock(&fSpinlock);
838	fCommandsActive |= 1;
839	fRegs->ci = 1;
840	FlushPostedWrites();
841	release_spinlock(&fSpinlock);
842	restore_interrupts(cpu);
843
844	int tfd;
845	status_t status = WaitForTransfer(&tfd, 20000000);
846
847	FLOW("tfd %#x\n", tfd);
848	FLOW("prdbc %ld\n", fCommandList->prdbc);
849	FLOW("ci   0x%08" B_PRIx32 "\n", fRegs->ci);
850	FLOW("is   0x%08" B_PRIx32 "\n", fRegs->is);
851	FLOW("serr 0x%08" B_PRIx32 "\n", fRegs->serr);
852
853/*
854	TRACE("ci   0x%08" B_PRIx32 "\n", fRegs->ci);
855	TRACE("ie   0x%08" B_PRIx32 "\n", fRegs->ie);
856	TRACE("is   0x%08" B_PRIx32 "\n", fRegs->is);
857	TRACE("cmd  0x%08" B_PRIx32 "\n", fRegs->cmd);
858	TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts);
859	TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl);
860	TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr);
861	TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact);
862	TRACE("tfd  0x%08" B_PRIx32 "\n", fRegs->tfd);
863*/
864
865	if (fResetPort || status == B_TIMED_OUT) {
866		fResetPort = false;
867		ResetPort();
868	}
869
870	size_t bytesTransfered = fCommandList->prdbc;
871
872	FinishTransfer();
873
874	if (status == B_TIMED_OUT) {
875		TRACE("ExecuteAtaRequest port %d: device timeout\n", fIndex);
876		request->abort();
877	} else {
878		request->finish(tfd, bytesTransfered);
879	}
880}
881
882
883void
884AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
885{
886//	TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
887
888	if (fIsATAPI) {
889		bool isWrite = false;
890		switch (request->flags & SCSI_DIR_MASK) {
891			case SCSI_DIR_NONE:
892				ASSERT(request->data_length == 0);
893				break;
894			case SCSI_DIR_IN:
895				ASSERT(request->data_length > 0);
896				break;
897			case SCSI_DIR_OUT:
898				isWrite = true;
899				ASSERT(request->data_length > 0);
900				break;
901			default:
902				panic("CDB has invalid direction mask");
903		}
904
905//		TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
906
907		sata_request *sreq = new(std::nothrow) sata_request(request);
908		if (sreq == NULL) {
909			TRACE("out of memory when allocating atapi request\n");
910			request->subsys_status = SCSI_REQ_ABORTED;
911			gSCSI->finished(request, 1);
912			return;
913		}
914
915		sreq->set_atapi_cmd(request->data_length);
916//		uint8 *data = (uint8*) sreq->ccb()->cdb;
917//		for (int i = 0; i < 16; i += 8) {
918//			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]);
919//		}
920		ExecuteSataRequest(sreq, isWrite);
921		return;
922	}
923
924	if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) {
925		panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");
926		return;
927	}
928
929	if (!fDevicePresent) {
930		TRACE("no device present on port %d\n", fIndex);
931		request->subsys_status = SCSI_DEV_NOT_THERE;
932		gSCSI->finished(request, 1);
933		return;
934	}
935
936	request->subsys_status = SCSI_REQ_CMP;
937
938	switch (request->cdb[0]) {
939		case SCSI_OP_TEST_UNIT_READY:
940			ScsiTestUnitReady(request);
941			break;
942		case SCSI_OP_INQUIRY:
943			ScsiInquiry(request);
944			break;
945		case SCSI_OP_READ_CAPACITY:
946			ScsiReadCapacity(request);
947			break;
948		case SCSI_OP_SERVICE_ACTION_IN:
949			if ((request->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16)
950				ScsiReadCapacity16(request);
951			else {
952				request->subsys_status = SCSI_REQ_INVALID;
953				gSCSI->finished(request, 1);
954			}
955			break;
956		case SCSI_OP_SYNCHRONIZE_CACHE:
957			ScsiSynchronizeCache(request);
958			break;
959		case SCSI_OP_READ_6:
960		case SCSI_OP_WRITE_6:
961		{
962			const scsi_cmd_rw_6 *cmd = (const scsi_cmd_rw_6 *)request->cdb;
963			uint32 position = ((uint32)cmd->high_lba << 16)
964				| ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba;
965			size_t length = cmd->length != 0 ? cmd->length : 256;
966			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6;
967			ScsiReadWrite(request, position, length, isWrite);
968			break;
969		}
970		case SCSI_OP_READ_10:
971		case SCSI_OP_WRITE_10:
972		{
973			const scsi_cmd_rw_10 *cmd = (const scsi_cmd_rw_10 *)request->cdb;
974			uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
975			size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length);
976			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10;
977			if (length) {
978				ScsiReadWrite(request, position, length, isWrite);
979			} else {
980				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
981					"data!\n");
982				request->subsys_status = SCSI_REQ_INVALID;
983				gSCSI->finished(request, 1);
984			}
985			break;
986		}
987		case SCSI_OP_READ_12:
988		case SCSI_OP_WRITE_12:
989		{
990			const scsi_cmd_rw_12 *cmd = (const scsi_cmd_rw_12 *)request->cdb;
991			uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
992			size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
993			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12;
994			if (length) {
995				ScsiReadWrite(request, position, length, isWrite);
996			} else {
997				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
998					"data!\n");
999				request->subsys_status = SCSI_REQ_INVALID;
1000				gSCSI->finished(request, 1);
1001			}
1002			break;
1003		}
1004		case SCSI_OP_READ_16:
1005		case SCSI_OP_WRITE_16:
1006		{
1007			const scsi_cmd_rw_16 *cmd = (const scsi_cmd_rw_16 *)request->cdb;
1008			uint64 position = B_BENDIAN_TO_HOST_INT64(cmd->lba);
1009			size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
1010			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_16;
1011			if (length) {
1012				ScsiReadWrite(request, position, length, isWrite);
1013			} else {
1014				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
1015					"data!\n");
1016				request->subsys_status = SCSI_REQ_INVALID;
1017				gSCSI->finished(request, 1);
1018			}
1019			break;
1020		}
1021		case SCSI_OP_WRITE_SAME_16:
1022		{
1023			const scsi_cmd_wsame_16 *cmd = (const scsi_cmd_wsame_16 *)request->cdb;
1024
1025			// SCSI unmap is used for trim, otherwise we don't support it
1026			if (!cmd->unmap) {
1027				TRACE("%s port %d: unsupported request opcode 0x%02x\n",
1028					__func__, fIndex, request->cdb[0]);
1029				request->subsys_status = SCSI_REQ_ABORTED;
1030				gSCSI->finished(request, 1);
1031				break;
1032			}
1033
1034			if (!fTrim) {
1035				// Drive doesn't support trim (or atapi)
1036				// Just say it was successful and quit
1037				request->subsys_status = SCSI_REQ_CMP;
1038			} else {
1039				TRACE("%s unimplemented: TRIM call\n", __func__);
1040				// TODO: Make Serial ATA (sata_request?) trim call here.
1041				request->subsys_status = SCSI_REQ_ABORTED;
1042			}
1043			gSCSI->finished(request, 1);
1044			break;
1045		}
1046		default:
1047			TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request "
1048				"opcode 0x%02x\n", fIndex, request->cdb[0]);
1049			request->subsys_status = SCSI_REQ_ABORTED;
1050			gSCSI->finished(request, 1);
1051	}
1052}
1053
1054
1055uchar
1056AHCIPort::ScsiAbortRequest(scsi_ccb *request)
1057{
1058
1059	return SCSI_REQ_CMP;
1060}
1061
1062
1063uchar
1064AHCIPort::ScsiTerminateRequest(scsi_ccb *request)
1065{
1066	return SCSI_REQ_CMP;
1067}
1068
1069
1070uchar
1071AHCIPort::ScsiResetDevice()
1072{
1073	return SCSI_REQ_CMP;
1074}
1075
1076
1077void
1078AHCIPort::ScsiGetRestrictions(bool *isATAPI, bool *noAutoSense,
1079	uint32 *maxBlocks)
1080{
1081	*isATAPI = fIsATAPI;
1082	*noAutoSense = fIsATAPI; // emulated auto sense for ATA, but not ATAPI
1083	*maxBlocks = fUse48BitCommands ? 65536 : 256;
1084	TRACE("AHCIPort::ScsiGetRestrictions port %d: isATAPI %d, noAutoSense %d, "
1085		"maxBlocks %" B_PRIu32 "\n", fIndex, *isATAPI, *noAutoSense, *maxBlocks);
1086}
1087