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