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