xref: /haiku/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp (revision 74252cefbcf266291fb069466189b4734eb05455)
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\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 
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 	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 
661 void
662 AHCIPort::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 
679 void
680 AHCIPort::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 
715 void
716 AHCIPort::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 
740 void
741 AHCIPort::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 
789 void
790 AHCIPort::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 
883 void
884 AHCIPort::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 
1055 uchar
1056 AHCIPort::ScsiAbortRequest(scsi_ccb *request)
1057 {
1058 
1059 	return SCSI_REQ_CMP;
1060 }
1061 
1062 
1063 uchar
1064 AHCIPort::ScsiTerminateRequest(scsi_ccb *request)
1065 {
1066 	return SCSI_REQ_CMP;
1067 }
1068 
1069 
1070 uchar
1071 AHCIPort::ScsiResetDevice()
1072 {
1073 	return SCSI_REQ_CMP;
1074 }
1075 
1076 
1077 void
1078 AHCIPort::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