xref: /haiku/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp (revision d9cebac2b77547b7064f22497514eecd2d047160)
1 /*
2  * Copyright 2007, Marcus Overhagen. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "ahci_port.h"
7 #include "ahci_controller.h"
8 #include "util.h"
9 #include "ata_cmds.h"
10 #include "scsi_cmds.h"
11 
12 #include <KernelExport.h>
13 #include <ByteOrder.h>
14 #include <stdio.h>
15 #include <string.h>
16 
17 #define TRACE(a...) dprintf("\33[34mahci:\33[0m " a)
18 // #define FLOW(a...)	dprintf("ahci: " a)
19 #define FLOW(a...)
20 //#define RWTRACE(a...) dprintf("\33[34mahci:\33[0m " a)
21 #define RWTRACE(a...)
22 
23 
24 AHCIPort::AHCIPort(AHCIController *controller, int index)
25 	: fIndex(index)
26 	, fRegs(&controller->fRegs->port[index])
27 	, fArea(-1)
28 	, fSpinlock(0)
29 	, fCommandsActive(0)
30 	, fRequestSem(-1)
31 	, fResponseSem(-1)
32 	, fDevicePresent(false)
33 	, fUse48BitCommands(false)
34 	, fSectorSize(0)
35 	, fSectorCount(0)
36 {
37 	fRequestSem = create_sem(1, "ahci request");
38 	fResponseSem = create_sem(0, "ahci response");
39 }
40 
41 
42 AHCIPort::~AHCIPort()
43 {
44 	delete_sem(fRequestSem);
45 	delete_sem(fResponseSem);
46 }
47 
48 
49 status_t
50 AHCIPort::Init1()
51 {
52 	TRACE("AHCIPort::Init1 port %d\n", fIndex);
53 
54 	size_t size = sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT + sizeof(fis) + sizeof(command_table) + sizeof(prd) * PRD_TABLE_ENTRY_COUNT;
55 
56 	char *virtAddr;
57 	char *physAddr;
58 
59 	fArea = alloc_mem((void **)&virtAddr, (void **)&physAddr, size, 0, "some AHCI port");
60 	if (fArea < B_OK) {
61 		TRACE("failed allocating memory for port %d\n", fIndex);
62 		return fArea;
63 	}
64 	memset(virtAddr, 0, size);
65 
66 	fCommandList = (command_list_entry *)virtAddr;
67 	virtAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT;
68 	fFIS = (fis *)virtAddr;
69 	virtAddr += sizeof(fis);
70 	fCommandTable = (command_table *)virtAddr;
71 	virtAddr += sizeof(command_table);
72 	fPRDTable = (prd *)virtAddr;
73 
74 	fRegs->clb  = LO32(physAddr);
75 	fRegs->clbu = HI32(physAddr);
76 	physAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT;
77 	fRegs->fb   = LO32(physAddr);
78 	fRegs->fbu  = HI32(physAddr);
79 	physAddr += sizeof(fis);
80 	fCommandList[0].ctba  = LO32(physAddr);
81 	fCommandList[0].ctbau = HI32(physAddr);
82 	// prdt follows after command table
83 
84 	// disable transitions to partial or slumber state
85 	fRegs->sctl |= 0x300;
86 
87 	// clear IRQ status bits
88 	fRegs->is = fRegs->is;
89 
90 	// clear error bits
91 	fRegs->serr = fRegs->serr;
92 
93 	// power up device
94 	fRegs->cmd |= PORT_CMD_POD;
95 
96 	// spin up device
97 	fRegs->cmd |= PORT_CMD_SUD;
98 
99 	// activate link
100 	fRegs->cmd = (fRegs->cmd & ~PORT_CMD_ICC_MASK) | PORT_CMD_ICC_ACTIVE;
101 
102 	// enable FIS receive
103 	fRegs->cmd |= PORT_CMD_FER;
104 
105 	FlushPostedWrites();
106 
107 	return B_OK;
108 }
109 
110 
111 // called with global interrupts enabled
112 status_t
113 AHCIPort::Init2()
114 {
115 	TRACE("AHCIPort::Init2 port %d\n", fIndex);
116 
117 	// start DMA engine
118 	fRegs->cmd |= PORT_CMD_ST;
119 
120 	// enable interrupts
121 	fRegs->ie = PORT_INT_MASK;
122 
123 	FlushPostedWrites();
124 
125 	ResetDevice();
126 	PostResetDevice();
127 
128 	TRACE("ie   0x%08lx\n", fRegs->ie);
129 	TRACE("is   0x%08lx\n", fRegs->is);
130 	TRACE("cmd  0x%08lx\n", fRegs->cmd);
131 	TRACE("ssts 0x%08lx\n", fRegs->ssts);
132 	TRACE("sctl 0x%08lx\n", fRegs->sctl);
133 	TRACE("serr 0x%08lx\n", fRegs->serr);
134 	TRACE("sact 0x%08lx\n", fRegs->sact);
135 	TRACE("tfd  0x%08lx\n", fRegs->tfd);
136 
137 	fDevicePresent = (fRegs->ssts & 0xf) == 0x3;
138 
139 	return B_OK;
140 }
141 
142 
143 void
144 AHCIPort::Uninit()
145 {
146 	TRACE("AHCIPort::Uninit port %d\n", fIndex);
147 
148 	// disable FIS receive
149 	fRegs->cmd &= ~PORT_CMD_FER;
150 
151 	// wait for receive completition, up to 500ms
152 	if (wait_until_clear(&fRegs->cmd, PORT_CMD_FR, 500000) < B_OK) {
153 		TRACE("AHCIPort::Uninit port %d error FIS rx still running\n", fIndex);
154 	}
155 
156 	// stop DMA engine
157 	fRegs->cmd &= ~PORT_CMD_ST;
158 
159 	// wait for DMA completition
160 	if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
161 		TRACE("AHCIPort::Uninit port %d error DMA engine still running\n", fIndex);
162 	}
163 
164 	// disable interrupts
165 	fRegs->ie = 0;
166 
167 	// clear pending interrupts
168 	fRegs->is = fRegs->is;
169 
170 	// invalidate DMA addresses
171 	fRegs->clb  = 0;
172 	fRegs->clbu = 0;
173 	fRegs->fb   = 0;
174 	fRegs->fbu  = 0;
175 
176 	delete_area(fArea);
177 }
178 
179 
180 status_t
181 AHCIPort::ResetDevice()
182 {
183 	TRACE("AHCIPort::ResetDevice port %d\n", fIndex);
184 
185 	// stop DMA engine
186 	fRegs->cmd &= ~PORT_CMD_ST;
187 	FlushPostedWrites();
188 
189 	if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
190 		TRACE("AHCIPort::ResetDevice port %d error DMA engine doesn't stop\n", fIndex);
191 	}
192 
193 	// perform a hard reset
194 	fRegs->sctl = (fRegs->sctl & ~0xf) | 1;
195 	FlushPostedWrites();
196 	spin(1100);
197 	fRegs->sctl &= ~0xf;
198 	FlushPostedWrites();
199 
200 	if (wait_until_set(&fRegs->ssts, 0x1, 100000) < B_OK) {
201 		TRACE("AHCIPort::ResetDevice port %d no device detected\n", fIndex);
202 	}
203 
204 	// clear error bits
205 	fRegs->serr = fRegs->serr;
206 	FlushPostedWrites();
207 
208 	if (fRegs->ssts & 1) {
209 		if (wait_until_set(&fRegs->ssts, 0x3, 500000) < B_OK) {
210 			TRACE("AHCIPort::ResetDevice port %d device present but no phy communication\n", fIndex);
211 		}
212 	}
213 
214 	// clear error bits
215 	fRegs->serr = fRegs->serr;
216 	FlushPostedWrites();
217 
218 	// start DMA engine
219 	fRegs->cmd |= PORT_CMD_ST;
220 	FlushPostedWrites();
221 
222 	return B_OK;
223 }
224 
225 
226 status_t
227 AHCIPort::PostResetDevice()
228 {
229 	TRACE("AHCIPort::PostResetDevice port %d\n", fIndex);
230 
231 	if ((fRegs->ssts & 0xf) != 0x3 || (fRegs->tfd & 0xff) == 0x7f) {
232 		TRACE("AHCIPort::PostResetDevice port %d: no device\n", fIndex);
233 		return B_OK;
234 	}
235 
236 	if ((fRegs->tfd & 0xff) == 0xff)
237 		snooze(200000);
238 
239 	if ((fRegs->tfd & 0xff) == 0xff) {
240 		TRACE("AHCIPort::PostResetDevice port %d: invalid task file status 0xff\n", fIndex);
241 		return B_ERROR;
242 	}
243 
244 	wait_until_clear(&fRegs->tfd, ATA_BSY, 31000000);
245 
246 	if (fRegs->sig == 0xeb140101)
247 		fRegs->cmd |= PORT_CMD_ATAPI;
248 	else
249 		fRegs->cmd &= ~PORT_CMD_ATAPI;
250 	FlushPostedWrites();
251 
252 	TRACE("device signature 0x%08lx (%s)\n", fRegs->sig,
253 		(fRegs->sig == 0xeb140101) ? "ATAPI" : (fRegs->sig == 0x00000101) ? "ATA" : "unknown");
254 
255 	return B_OK;
256 }
257 
258 
259 void
260 AHCIPort::DumpD2HFis()
261 {
262 	TRACE("D2H FIS:\n");
263 	TRACE("  DW0  %02x %02x %02x %02x\n", fFIS->rfis[3], fFIS->rfis[2], fFIS->rfis[1], fFIS->rfis[0]);
264 	TRACE("  DW1  %02x %02x %02x %02x\n", fFIS->rfis[7], fFIS->rfis[6], fFIS->rfis[5], fFIS->rfis[4]);
265 	TRACE("  DW2  %02x %02x %02x %02x\n", fFIS->rfis[11], fFIS->rfis[10], fFIS->rfis[9], fFIS->rfis[8]);
266 	TRACE("  DW3  %02x %02x %02x %02x\n", fFIS->rfis[15], fFIS->rfis[14], fFIS->rfis[13], fFIS->rfis[12]);
267 	TRACE("  DW4  %02x %02x %02x %02x\n", fFIS->rfis[19], fFIS->rfis[18], fFIS->rfis[17], fFIS->rfis[16]);
268 }
269 
270 
271 void
272 AHCIPort::Interrupt()
273 {
274 	uint32 is = fRegs->is;
275 	uint32 ci = fRegs->ci;
276 	fRegs->is = is; // clear interrupts
277 
278 	RWTRACE("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
279 
280 	if (is & PORT_INT_ERROR)
281 		TRACE("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
282 
283 	if (is & PORT_INT_FATAL)
284 		panic("ahci fatal error, is 0x%08lx", is);
285 
286 	int release = 0;
287 
288 	acquire_spinlock(&fSpinlock);
289 	if ((fCommandsActive & 1) && !(ci & 1)) {
290 		release = 1;
291 		fCommandsActive &= ~1;
292 	}
293 	release_spinlock(&fSpinlock);
294 
295 	if (release)
296 		release_sem_etc(fResponseSem, 1, B_RELEASE_IF_WAITING_ONLY | B_DO_NOT_RESCHEDULE);
297 }
298 
299 
300 status_t
301 AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize)
302 {
303 	int peMax = prdMax + 1;
304 	physical_entry pe[peMax];
305 	if (get_memory_map(data, dataSize, pe, peMax ) < B_OK) {
306 		TRACE("AHCIPort::FillPrdTable get_memory_map failed\n");
307 		return B_ERROR;
308 	}
309 	int peUsed;
310 	for (peUsed = 0; pe[peUsed].size; peUsed++)
311 		;
312 	return FillPrdTable(prdTable, prdCount, prdMax, pe, peUsed, dataSize);
313 }
314 
315 
316 status_t
317 AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize)
318 {
319 	*prdCount = 0;
320 	while (sgCount > 0 && dataSize > 0) {
321 		size_t size = min_c(sgTable->size, dataSize);
322 		void *address = sgTable->address;
323 		FLOW("FillPrdTable: sg-entry addr %p, size %lu\n", address, size);
324 		if ((uint32)address & 1) {
325 			TRACE("AHCIPort::FillPrdTable: data alignment error\n");
326 			return B_ERROR;
327 		}
328 		dataSize -= size;
329 		while (size > 0) {
330 			size_t bytes = min_c(size, PRD_MAX_DATA_LENGTH);
331 			if (*prdCount == prdMax) {
332 				TRACE("AHCIPort::FillPrdTable: prd table exhausted\n");
333 				return B_ERROR;
334 			}
335 			FLOW("FillPrdTable: prd-entry %u, addr %p, size %lu\n", *prdCount, address, bytes);
336 			prdTable->dba  = LO32(address);
337 			prdTable->dbau = HI32(address);
338 			prdTable->res  = 0;
339 			prdTable->dbc  = bytes - 1;
340 			*prdCount += 1;
341 			prdTable++;
342 			address = (char *)address + bytes;
343 			size -= bytes;
344 		}
345 		sgTable++;
346 		sgCount--;
347 	}
348 	if (*prdCount == 0) {
349 		TRACE("AHCIPort::FillPrdTable: count is 0\n");
350 		return B_ERROR;
351 	}
352 	if (dataSize > 0) {
353 		TRACE("AHCIPort::FillPrdTable: sg table %ld bytes too small\n", dataSize);
354 		return B_ERROR;
355 	}
356 	return B_OK;
357 }
358 
359 
360 void
361 AHCIPort::StartTransfer()
362 {
363 	acquire_sem(fRequestSem);
364 }
365 
366 
367 status_t
368 AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout)
369 {
370 	status_t result = B_OK;
371 	if (acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout) < B_OK) {
372 		fCommandsActive &= ~1;
373 		result = B_TIMED_OUT;
374 	} else {
375 		*tfd = fRegs->tfd;
376 	}
377 	return result;
378 }
379 
380 
381 void
382 AHCIPort::FinishTransfer()
383 {
384 	release_sem(fRequestSem);
385 }
386 
387 
388 void
389 AHCIPort::ScsiTestUnitReady(scsi_ccb *request)
390 {
391 	TRACE("AHCIPort::ScsiTestUnitReady port %d\n", fIndex);
392 	request->subsys_status = SCSI_REQ_CMP;
393 	gSCSI->finished(request, 1);
394 }
395 
396 
397 void
398 AHCIPort::ScsiInquiry(scsi_ccb *request)
399 {
400 	TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex);
401 
402 	scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)request->cdb;
403 	scsi_res_inquiry scsiData;
404 	ata_res_identify_device	ataData;
405 
406 	if (cmd->evpd || cmd->page_code) {
407 		TRACE("invalid request\n");
408 		request->subsys_status = SCSI_REQ_ABORTED;
409 		gSCSI->finished(request, 1);
410 		return;
411 	}
412 
413 	memset(&ataData, 0, sizeof(ataData));
414 
415 	StartTransfer();
416 
417 	int prdEntrys;
418 	FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, &ataData, sizeof(ataData));
419 
420 
421 	FLOW("prdEntrys %d\n", prdEntrys);
422 
423 	memset((void *)fCommandTable->cfis, 0, 5 * 4);
424 	fCommandTable->cfis[0] = 0x27;
425 	fCommandTable->cfis[1] = 0x80;
426 	fCommandTable->cfis[2] = 0xec;
427 
428 
429 	fCommandList->prdtl_flags_cfl = 0;
430 	fCommandList->prdtl = prdEntrys;
431 	fCommandList->cfl = 5;
432 	fCommandList->prdbc = 0;
433 
434 	if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 4000000) < B_OK) {
435 		TRACE("device is busy\n");
436 		FinishTransfer();
437 		request->subsys_status = SCSI_REQ_ABORTED;
438 		gSCSI->finished(request, 1);
439 		return;
440 	}
441 
442 	cpu_status cpu = disable_interrupts();
443 	acquire_spinlock(&fSpinlock);
444 	fRegs->ci |= 1;
445 	FlushPostedWrites();
446 	fCommandsActive |= 1;
447 	release_spinlock(&fSpinlock);
448 	restore_interrupts(cpu);
449 
450 	int status;
451 	WaitForTransfer(&status, 100000);
452 
453 	FLOW("prdbc %ld\n", fCommandList->prdbc);
454 	FLOW("ci   0x%08lx\n", fRegs->ci);
455 	FLOW("is   0x%08lx\n", fRegs->is);
456 	FLOW("serr 0x%08lx\n", fRegs->serr);
457 
458 /*
459 	TRACE("ci   0x%08lx\n", fRegs->ci);
460 	TRACE("ie   0x%08lx\n", fRegs->ie);
461 	TRACE("is   0x%08lx\n", fRegs->is);
462 	TRACE("cmd  0x%08lx\n", fRegs->cmd);
463 	TRACE("ssts 0x%08lx\n", fRegs->ssts);
464 	TRACE("sctl 0x%08lx\n", fRegs->sctl);
465 	TRACE("serr 0x%08lx\n", fRegs->serr);
466 	TRACE("sact 0x%08lx\n", fRegs->sact);
467 	TRACE("tfd  0x%08lx\n", fRegs->tfd);
468 
469 	uint8 *data = (uint8*) &ataData;
470 	for (int i = 0; i < 512; i += 8) {
471 		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]);
472 	}
473 */
474 	scsiData.device_type = scsi_dev_direct_access;
475 	scsiData.device_qualifier = scsi_periph_qual_connected;
476 	scsiData.device_type_modifier = 0;
477 	scsiData.removable_medium = false;
478 	scsiData.ansi_version = 2;
479 	scsiData.ecma_version = 0;
480 	scsiData.iso_version = 0;
481 	scsiData.response_data_format = 2;
482 	scsiData.term_iop = false;
483 	scsiData.additional_length = sizeof(scsiData) - 4;
484 	scsiData.soft_reset = false;
485 	scsiData.cmd_queue = false;
486 	scsiData.linked = false;
487 	scsiData.sync = false;
488 	scsiData.write_bus16 = true;
489 	scsiData.write_bus32 = false;
490 	scsiData.relative_address = false;
491 	memcpy(scsiData.vendor_ident, ataData.model_number, sizeof(scsiData.vendor_ident));
492 	memcpy(scsiData.product_ident, ataData.model_number + 8, sizeof(scsiData.product_ident));
493 	memcpy(scsiData.product_rev, ataData.serial_number, sizeof(scsiData.product_rev));
494 
495 	bool lba			= (ataData.words[49] & (1 << 9)) != 0;
496 	bool lba48			= (ataData.words[83] & (1 << 10)) != 0;
497 	uint32 sectors		= *(uint32*)&ataData.words[60];
498 	uint64 sectors48	= *(uint64*)&ataData.words[100];
499 	fUse48BitCommands   = lba && lba48;
500 	fSectorSize			= 512;
501 	fSectorCount		= !(lba || sectors) ? 0 : lba48 ? sectors48 : sectors;
502 
503 #if 0
504 	if (fSectorCount < 0x0fffffff) {
505 		TRACE("disabling 48 bit commands\n");
506 		fUse48BitCommands = 0;
507 	}
508 #endif
509 
510 	char modelNumber[sizeof(ataData.model_number) + 1];
511 	char serialNumber[sizeof(ataData.serial_number) + 1];
512 	char firmwareRev[sizeof(ataData.firmware_revision) + 1];
513 
514 	strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber));
515 	strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber));
516 	strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev));
517 
518 	swap_words(modelNumber, sizeof(modelNumber) - 1);
519 	swap_words(serialNumber, sizeof(serialNumber) - 1);
520 	swap_words(firmwareRev, sizeof(firmwareRev) - 1);
521 
522 	TRACE("model number:  %s\n", modelNumber);
523 	TRACE("serial number: %s\n", serialNumber);
524   	TRACE("firmware rev.: %s\n", firmwareRev);
525 	TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %lu, sectors48 %llu, size %llu\n",
526 		lba, lba48, fUse48BitCommands, sectors, sectors48, fSectorCount * fSectorSize);
527 
528 	if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, sizeof(scsiData)) < B_OK) {
529 		request->subsys_status = SCSI_DATA_RUN_ERR;
530 	} else {
531 		request->subsys_status = SCSI_REQ_CMP;
532 		request->data_resid = request->data_length - sizeof(scsiData);// ???
533 		request->data_length = sizeof(scsiData); // ???
534 	}
535 
536 	FinishTransfer();
537 
538 	gSCSI->finished(request, 1);
539 }
540 
541 
542 void
543 AHCIPort::ScsiReadCapacity(scsi_ccb *request)
544 {
545 	TRACE("AHCIPort::ScsiReadCapacity port %d\n", fIndex);
546 
547 	scsi_cmd_read_capacity *cmd = (scsi_cmd_read_capacity *)request->cdb;
548 	scsi_res_read_capacity scsiData;
549 
550 	if (cmd->pmi || cmd->lba) {
551 		TRACE("invalid request\n");
552 		return;
553 	}
554 
555 	TRACE("SectorSize %lu, SectorCount 0x%llx\n", fSectorSize, fSectorCount);
556 
557 	if (fSectorCount > 0xffffffff)
558 		panic("ahci: SCSI emulation doesn't support harddisks larger than 2TB");
559 
560 	scsiData.block_size = B_HOST_TO_BENDIAN_INT32(fSectorSize);
561 	scsiData.lba = B_HOST_TO_BENDIAN_INT32(fSectorCount - 1);
562 
563 	if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, sizeof(scsiData)) < B_OK) {
564 		request->subsys_status = SCSI_DATA_RUN_ERR;
565 	} else {
566 		request->subsys_status = SCSI_REQ_CMP;
567 		request->data_resid = request->data_length - sizeof(scsiData);// ???
568 		request->data_length = sizeof(scsiData); // ???
569 	}
570 	gSCSI->finished(request, 1);
571 }
572 
573 
574 void
575 AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool isWrite)
576 {
577 	uint32 bytecount = length * 512;
578 
579 	RWTRACE("ScsiReadWrite: position %llu, size %lu, isWrite %d\n", position * 512, bytecount, isWrite);
580 
581 #if 0
582 	if (isWrite) {
583 		TRACE("write request ignored\n");
584 		request->subsys_status = SCSI_REQ_CMP;
585 		request->data_resid = 0;
586 		gSCSI->finished(request, 1);
587 		return;
588 	}
589 #endif
590 
591 	StartTransfer();
592 
593 	int prdEntrys;
594 	FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->sg_list, request->sg_count, bytecount);
595 
596 	FLOW("prdEntrys %d\n", prdEntrys);
597 
598 	memset((void *)fCommandTable->cfis, 0, 5 * 4);
599 
600 	if (fUse48BitCommands) {
601 		if (length > 65536)
602 			panic("ahci: ScsiReadWrite length too large, %lu sectors", length);
603 		fCommandTable->cfis[0] = 0x27;
604 		fCommandTable->cfis[1] = 0x80;
605 		fCommandTable->cfis[2] = isWrite ? 0x35 : 0x25;
606 		fCommandTable->cfis[4] = position & 0xff;
607 		fCommandTable->cfis[5] = (position >> 8) & 0xff;
608 		fCommandTable->cfis[6] = (position >> 16) & 0xff;
609 		fCommandTable->cfis[7] = 0x40;
610 		fCommandTable->cfis[8] = (position >> 24) & 0xff;
611 		fCommandTable->cfis[9] = (position >> 32) & 0xff;
612 		fCommandTable->cfis[10] = (position >> 40) & 0xff;
613 		fCommandTable->cfis[12] = length & 0xff;
614 		fCommandTable->cfis[13] = (length >> 8) & 0xff;
615 	} else {
616 		if (length > 256)
617 			panic("ahci: ScsiReadWrite length too large, %lu sectors", length);
618 		if (position > 0x0fffffff)
619 			panic("achi: ScsiReadWrite position too large for non-48-bit LBA\n");
620 		fCommandTable->cfis[0] = 0x27;
621 		fCommandTable->cfis[1] = 0x80;
622 		fCommandTable->cfis[2] = isWrite ? 0xca : 0xc8;
623 		fCommandTable->cfis[4] = position & 0xff;
624 		fCommandTable->cfis[5] = (position >> 8) & 0xff;
625 		fCommandTable->cfis[6] = (position >> 16) & 0xff;
626 		fCommandTable->cfis[7] = 0x40 | ((position >> 24) & 0x0f);
627 		fCommandTable->cfis[12] = length & 0xff;
628 	}
629 
630 	fCommandList->prdtl_flags_cfl = 0;
631 	fCommandList->prdtl = prdEntrys;
632 	fCommandList->cfl = 5;
633 	if (isWrite)
634 		fCommandList->w = 1;
635 	fCommandList->prdbc = 0;
636 
637 	if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 4000000) < B_OK) {
638 		TRACE("device is busy\n");
639 		FinishTransfer();
640 		request->subsys_status = SCSI_REQ_ABORTED;
641 		gSCSI->finished(request, 1);
642 		return;
643 	}
644 	cpu_status cpu = disable_interrupts();
645 	acquire_spinlock(&fSpinlock);
646 	fRegs->ci |= 1;
647 	FlushPostedWrites();
648 	fCommandsActive |= 1;
649 	release_spinlock(&fSpinlock);
650 	restore_interrupts(cpu);
651 
652 	int tfd;
653 	status_t status = WaitForTransfer(&tfd, 4000000);
654 
655 	FLOW("prdbc %ld\n", fCommandList->prdbc);
656 
657 	if (status < B_OK || (tfd & ATA_ERR)) {
658 		TRACE("device error\n");
659 		request->subsys_status = SCSI_REQ_ABORTED;
660 	} else if (fCommandList->prdbc != bytecount) {
661 		TRACE("should never happen\n");
662 		request->subsys_status = SCSI_REQ_CMP_ERR;
663 	} else {
664 		request->subsys_status = SCSI_REQ_CMP;
665 	}
666 	request->data_resid = request->data_length - fCommandList->prdbc;// ???
667 	request->data_length = fCommandList->prdbc; // ???
668 
669 	FinishTransfer();
670 
671 	gSCSI->finished(request, 1);
672 }
673 
674 
675 void
676 AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
677 {
678 
679 //	TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
680 
681 	if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) {
682 		panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");
683 		return;
684 	}
685 
686 	if (!fDevicePresent) {
687 		TRACE("no such device!\n");
688 		request->subsys_status = SCSI_DEV_NOT_THERE;
689 		gSCSI->finished(request, 1);
690 		return;
691 	}
692 
693 	request->subsys_status = SCSI_REQ_CMP;
694 
695 	switch (request->cdb[0]) {
696 		case SCSI_OP_TEST_UNIT_READY:
697 			ScsiTestUnitReady(request);
698 			break;
699 		case SCSI_OP_INQUIRY:
700 			ScsiInquiry(request);
701 			break;
702 		case SCSI_OP_READ_CAPACITY:
703 			ScsiReadCapacity(request);
704 			break;
705 		case SCSI_OP_READ_6:
706 		case SCSI_OP_WRITE_6:
707 		{
708 			scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb;
709 			uint32 position = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba;
710 			size_t length = cmd->length != 0 ? cmd->length : 256;
711 			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6;
712 			ScsiReadWrite(request, position, length, isWrite);
713 			break;
714 		}
715 		case SCSI_OP_READ_10:
716 		case SCSI_OP_WRITE_10:
717 		{
718 			scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb;
719 			uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
720 			size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length);
721 			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10;
722 			if (length) {
723 				ScsiReadWrite(request, position, length, isWrite);
724 			} else {
725 				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without data!\n");
726 				request->subsys_status = SCSI_REQ_INVALID;
727 				gSCSI->finished(request, 1);
728 			}
729 			break;
730 		}
731 		case SCSI_OP_READ_12:
732 		case SCSI_OP_WRITE_12:
733 		{
734 			scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb;
735 			uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
736 			size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
737 			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12;
738 			if (length) {
739 				ScsiReadWrite(request, position, length, isWrite);
740 			} else {
741 				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without data!\n");
742 				request->subsys_status = SCSI_REQ_INVALID;
743 				gSCSI->finished(request, 1);
744 			}
745 			break;
746 		}
747 		default:
748 			TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request opcode 0x%02x\n", fIndex, request->cdb[0]);
749 			request->subsys_status = SCSI_REQ_ABORTED;
750 			gSCSI->finished(request, 1);
751 	}
752 }
753 
754 
755 uchar
756 AHCIPort::ScsiAbortRequest(scsi_ccb *request)
757 {
758 
759 	return SCSI_REQ_CMP;
760 }
761 
762 
763 uchar
764 AHCIPort::ScsiTerminateRequest(scsi_ccb *request)
765 {
766 	return SCSI_REQ_CMP;
767 }
768 
769 
770 uchar
771 AHCIPort::ScsiResetDevice()
772 {
773 	return SCSI_REQ_CMP;
774 }
775