btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / add-ons / kernel / busses / scsi / ahci / ahci_port.cpp
blob0ec9a166f9701c1bd69a97d5d81f87cfd8eb3d74
1 /*
2 * Copyright 2008-2015 Haiku, Inc. All rights reserved.
3 * Copyright 2007-2009, Marcus Overhagen. All rights reserved.
4 * Distributed under the terms of the MIT License.
6 * Authors:
7 * Axel Dörfler, axeld@pinc-software.de
8 * Michael Lotz, mmlr@mlotz.ch
9 * Alexander von Gluck IV, kallisti5@unixzen.com
13 #include "ahci_port.h"
15 #include <new>
16 #include <stdio.h>
17 #include <string.h>
19 #include <ByteOrder.h>
20 #include <KernelExport.h>
22 #include <ATACommands.h>
23 #include <ATAInfoBlock.h>
24 #include <AutoDeleter.h>
26 #include "ahci_controller.h"
27 #include "ahci_tracing.h"
28 #include "sata_request.h"
29 #include "scsi_cmds.h"
30 #include "util.h"
33 //#define TRACE_AHCI
34 #ifdef TRACE_AHCI
35 # define TRACE(a...) dprintf("ahci: " a)
36 #else
37 # define TRACE(a...)
38 #endif
40 #define ERROR(a...) dprintf("ahci: " a)
41 //#define FLOW(a...) dprintf("ahci: " a)
42 //#define RWTRACE(a...) dprintf("ahci: " a)
43 #define FLOW(a...)
44 #define RWTRACE(a...)
47 AHCIPort::AHCIPort(AHCIController* controller, int index)
49 fController(controller),
50 fIndex(index),
51 fRegs(&controller->fRegs->port[index]),
52 fArea(-1),
53 fCommandsActive(0),
54 fRequestSem(-1),
55 fResponseSem(-1),
56 fDevicePresent(false),
57 fUse48BitCommands(false),
58 fSectorSize(0),
59 fSectorCount(0),
60 fIsATAPI(false),
61 fTestUnitReadyActive(false),
62 fPortReset(false),
63 fError(false),
64 fTrimSupported(false)
66 B_INITIALIZE_SPINLOCK(&fSpinlock);
67 fRequestSem = create_sem(1, "ahci request");
68 fResponseSem = create_sem(0, "ahci response");
72 AHCIPort::~AHCIPort()
74 delete_sem(fRequestSem);
75 delete_sem(fResponseSem);
79 status_t
80 AHCIPort::Init1()
82 TRACE("AHCIPort::Init1 port %d\n", fIndex);
84 size_t size = sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT
85 + sizeof(fis) + sizeof(command_table)
86 + sizeof(prd) * PRD_TABLE_ENTRY_COUNT;
88 char* virtAddr;
89 phys_addr_t physAddr;
90 char name[32];
91 snprintf(name, sizeof(name), "AHCI port %d", fIndex);
93 fArea = alloc_mem((void**)&virtAddr, &physAddr, size, 0, name);
94 if (fArea < B_OK) {
95 TRACE("failed allocating memory for port %d\n", fIndex);
96 return fArea;
98 memset(virtAddr, 0, size);
100 fCommandList = (command_list_entry*)virtAddr;
101 virtAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT;
102 fFIS = (fis*)virtAddr;
103 virtAddr += sizeof(fis);
104 fCommandTable = (command_table*)virtAddr;
105 virtAddr += sizeof(command_table);
106 fPRDTable = (prd*)virtAddr;
107 TRACE("PRD table is at %p\n", fPRDTable);
109 fRegs->clb = LO32(physAddr);
110 fRegs->clbu = HI32(physAddr);
111 physAddr += sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT;
112 fRegs->fb = LO32(physAddr);
113 fRegs->fbu = HI32(physAddr);
114 physAddr += sizeof(fis);
115 fCommandList[0].ctba = LO32(physAddr);
116 fCommandList[0].ctbau = HI32(physAddr);
117 // prdt follows after command table
119 // disable transitions to partial or slumber state
120 fRegs->sctl |= (SCTL_PORT_IPM_NOPART | SCTL_PORT_IPM_NOSLUM);
122 // clear IRQ status bits
123 fRegs->is = fRegs->is;
125 // clear error bits
126 _ClearErrorRegister();
128 // power up device
129 fRegs->cmd |= PORT_CMD_POD;
131 // spin up device
132 fRegs->cmd |= PORT_CMD_SUD;
134 // activate link
135 fRegs->cmd = (fRegs->cmd & ~PORT_CMD_ICC_MASK) | PORT_CMD_ICC_ACTIVE;
137 // enable FIS receive (enabled when fb set, only to be disabled when unset)
138 fRegs->cmd |= PORT_CMD_FRE;
140 FlushPostedWrites();
142 return B_OK;
146 // called with global interrupts enabled
147 status_t
148 AHCIPort::Init2()
150 TRACE("AHCIPort::Init2 port %d\n", fIndex);
152 // enable port
153 Enable();
155 // enable interrupts
156 fRegs->ie = PORT_INT_MASK;
158 FlushPostedWrites();
160 // reset port and probe info
161 ResetDevice();
163 DumpHBAState();
165 TRACE("%s: port %d, device %s\n", __func__, fIndex,
166 fDevicePresent ? "present" : "absent");
168 return B_OK;
172 void
173 AHCIPort::Uninit()
175 TRACE("AHCIPort::Uninit port %d\n", fIndex);
177 // Spec v1.3.1, §10.3.2 - Shut down port before unsetting FRE
179 // shutdown the port
180 if (!Disable()) {
181 ERROR("%s: port %d error, unable to shutdown before FRE clear!\n",
182 __func__, fIndex);
183 return;
186 // Clear FRE and wait for completion
187 fRegs->cmd &= ~PORT_CMD_FRE;
188 if (wait_until_clear(&fRegs->cmd, PORT_CMD_FR, 500000) < B_OK)
189 ERROR("%s: port %d error FIS rx still running\n", __func__, fIndex);
191 // disable interrupts
192 fRegs->ie = 0;
194 // clear pending interrupts
195 fRegs->is = fRegs->is;
197 // invalidate DMA addresses
198 fRegs->clb = 0;
199 fRegs->clbu = 0;
200 fRegs->fb = 0;
201 fRegs->fbu = 0;
203 delete_area(fArea);
207 void
208 AHCIPort::ResetDevice()
210 // perform a hard reset
211 if (PortReset() != B_OK) {
212 ERROR("%s: port %d unable to hard reset device\n", __func__, fIndex);
213 return;
216 if (wait_until_set(&fRegs->ssts, SSTS_PORT_DET_NODEV, 100000) < B_OK)
217 TRACE("AHCIPort::ResetDevice port %d no device detected\n", fIndex);
219 _ClearErrorRegister();
221 if (fRegs->ssts & SSTS_PORT_DET_NOPHY) {
222 if (wait_until_set(&fRegs->ssts, 0x3, 500000) < B_OK) {
223 TRACE("AHCIPort::ResetDevice port %d device present but no phy "
224 "communication\n", fIndex);
228 _ClearErrorRegister();
232 status_t
233 AHCIPort::PortReset()
235 TRACE("AHCIPort::PortReset port %d\n", fIndex);
237 if (!Disable()) {
238 ERROR("%s: port %d unable to shutdown!\n", __func__, fIndex);
239 return B_ERROR;
242 _ClearErrorRegister();
244 // Wait for BSY and DRQ to clear (idle port)
245 if (wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST,
246 1000000) < B_OK) {
247 // If we can't clear busy, do a full comreset
249 // Spec v1.3.1, §10.4.2 Port Reset
250 // Physical comm between HBA and port disabled. More Intrusive
251 ERROR("%s: port %d undergoing COMRESET\n", __func__, fIndex);
253 // Notice we're throwing out all other control flags.
254 fRegs->sctl = (SSTS_PORT_IPM_ACTIVE | SSTS_PORT_IPM_PARTIAL
255 | SCTL_PORT_DET_INIT);
256 FlushPostedWrites();
257 spin(1100);
258 // You must wait 1ms at minimum
259 fRegs->sctl = (fRegs->sctl & ~HBA_PORT_DET_MASK) | SCTL_PORT_DET_NOINIT;
260 FlushPostedWrites();
263 Enable();
265 if (wait_until_set(&fRegs->ssts, SSTS_PORT_DET_PRESENT, 500000) < B_OK) {
266 TRACE("%s: port %d: no device detected\n", __func__, fIndex);
267 fDevicePresent = false;
268 return B_OK;
271 return Probe();
275 status_t
276 AHCIPort::Probe()
278 if ((fRegs->tfd & 0xff) == 0xff)
279 snooze(200000);
281 if ((fRegs->tfd & 0xff) == 0xff) {
282 TRACE("%s: port %d: invalid task file status 0xff\n", __func__,
283 fIndex);
284 return B_ERROR;
287 if (!fTestUnitReadyActive) {
288 switch (fRegs->ssts & HBA_PORT_SPD_MASK) {
289 case 0x10:
290 ERROR("%s: port %d link speed 1.5Gb/s\n", __func__, fIndex);
291 break;
292 case 0x20:
293 ERROR("%s: port %d link speed 3.0Gb/s\n", __func__, fIndex);
294 break;
295 case 0x30:
296 ERROR("%s: port %d link speed 6.0Gb/s\n", __func__, fIndex);
297 break;
298 default:
299 ERROR("%s: port %d link speed unrestricted\n", __func__, fIndex);
300 break;
304 wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY, 31000000);
306 fDevicePresent = (fRegs->ssts & HBA_PORT_DET_MASK) == SSTS_PORT_DET_PRESENT;
307 fIsATAPI = fRegs->sig == SATA_SIG_ATAPI;
309 if (fIsATAPI)
310 fRegs->cmd |= PORT_CMD_ATAPI;
311 else
312 fRegs->cmd &= ~PORT_CMD_ATAPI;
313 FlushPostedWrites();
315 TRACE("device signature 0x%08" B_PRIx32 " (%s)\n", fRegs->sig,
316 fRegs->sig == SATA_SIG_ATAPI ? "ATAPI" : fRegs->sig == SATA_SIG_ATA
317 ? "ATA" : "unknown");
319 return B_OK;
323 void
324 AHCIPort::DumpD2HFis()
326 TRACE("D2H FIS:\n");
327 TRACE(" DW0 %02x %02x %02x %02x\n", fFIS->rfis[3], fFIS->rfis[2],
328 fFIS->rfis[1], fFIS->rfis[0]);
329 TRACE(" DW1 %02x %02x %02x %02x\n", fFIS->rfis[7], fFIS->rfis[6],
330 fFIS->rfis[5], fFIS->rfis[4]);
331 TRACE(" DW2 %02x %02x %02x %02x\n", fFIS->rfis[11], fFIS->rfis[10],
332 fFIS->rfis[9], fFIS->rfis[8]);
333 TRACE(" DW3 %02x %02x %02x %02x\n", fFIS->rfis[15], fFIS->rfis[14],
334 fFIS->rfis[13], fFIS->rfis[12]);
335 TRACE(" DW4 %02x %02x %02x %02x\n", fFIS->rfis[19], fFIS->rfis[18],
336 fFIS->rfis[17], fFIS->rfis[16]);
340 void
341 AHCIPort::DumpHBAState()
343 TRACE("Port %d state:\n", fIndex);
344 TRACE(" ie 0x%08" B_PRIx32 "\n", fRegs->ie);
345 TRACE(" is 0x%08" B_PRIx32 "\n", fRegs->is);
346 TRACE(" cmd 0x%08" B_PRIx32 "\n", fRegs->cmd);
347 TRACE(" ssts 0x%08" B_PRIx32 "\n", fRegs->ssts);
348 TRACE(" sctl 0x%08" B_PRIx32 "\n", fRegs->sctl);
349 TRACE(" serr 0x%08" B_PRIx32 "\n", fRegs->serr);
350 TRACE(" sact 0x%08" B_PRIx32 "\n", fRegs->sact);
351 TRACE(" tfd 0x%08" B_PRIx32 "\n", fRegs->tfd);
355 void
356 AHCIPort::Interrupt()
358 uint32 is = fRegs->is;
359 fRegs->is = is; // clear interrupts
361 if (is & PORT_INT_ERROR) {
362 InterruptErrorHandler(is);
363 return;
366 uint32 ci = fRegs->ci;
368 RWTRACE("[%lld] %ld AHCIPort::Interrupt port %d, fCommandsActive 0x%08"
369 B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n",
370 system_time(), find_thread(NULL), fIndex, fCommandsActive, is, ci);
372 acquire_spinlock(&fSpinlock);
373 if ((fCommandsActive & 1) && !(ci & 1)) {
374 fCommandsActive &= ~1;
375 release_sem_etc(fResponseSem, 1, B_DO_NOT_RESCHEDULE);
377 release_spinlock(&fSpinlock);
381 void
382 AHCIPort::InterruptErrorHandler(uint32 is)
384 TRACE("AHCIPort::InterruptErrorHandler port %d, fCommandsActive 0x%08"
385 B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", fIndex,
386 fCommandsActive, is, fRegs->ci);
387 TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts);
388 TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl);
389 TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr);
390 TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact);
392 // read and clear SError
393 _ClearErrorRegister();
395 if (is & PORT_INT_TFE) {
396 TRACE("Task File Error\n");
398 fPortReset = true;
399 fError = true;
401 if (is & PORT_INT_HBF) {
402 ERROR("Host Bus Fatal Error\n");
403 fPortReset = true;
404 fError = true;
406 if (is & PORT_INT_HBD) {
407 ERROR("Host Bus Data Error\n");
408 fPortReset = true;
409 fError = true;
411 if (is & PORT_INT_IF) {
412 ERROR("Interface Fatal Error\n");
413 fPortReset = true;
414 fError = true;
416 if (is & PORT_INT_INF) {
417 TRACE("Interface Non Fatal Error\n");
419 if (is & PORT_INT_OF) {
420 TRACE("Overflow\n");
421 fPortReset = true;
422 fError = true;
424 if (is & PORT_INT_IPM) {
425 TRACE("Incorrect Port Multiplier Status\n");
427 if (is & PORT_INT_PRC) {
428 TRACE("PhyReady Change\n");
429 //fPortReset = true;
431 if (is & PORT_INT_PC) {
432 TRACE("Port Connect Change\n");
433 // Unsolicited when we had a port connect change without us requesting
434 // Spec v1.3, §6.2.2.3 Recovery of Unsolicited COMINIT
436 // XXX: This shouldn't be needed here... but we can loop without it
437 //_ClearErrorRegister();
439 if (is & PORT_INT_UF) {
440 TRACE("Unknown FIS\n");
441 fPortReset = true;
444 if (fError) {
445 acquire_spinlock(&fSpinlock);
446 if ((fCommandsActive & 1)) {
447 fCommandsActive &= ~1;
448 release_sem_etc(fResponseSem, 1, B_DO_NOT_RESCHEDULE);
450 release_spinlock(&fSpinlock);
455 status_t
456 AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax,
457 const void* data, size_t dataSize)
459 int maxEntries = prdMax + 1;
460 physical_entry entries[maxEntries];
461 uint32 entriesUsed = maxEntries;
463 status_t status = get_memory_map_etc(B_CURRENT_TEAM, data, dataSize,
464 entries, &entriesUsed);
465 if (status != B_OK) {
466 ERROR("%s: get_memory_map() failed: %s\n", __func__, strerror(status));
467 return B_ERROR;
470 return FillPrdTable(prdTable, prdCount, prdMax, entries, entriesUsed,
471 dataSize);
475 status_t
476 AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax,
477 const physical_entry* sgTable, int sgCount, size_t dataSize)
479 *prdCount = 0;
480 while (sgCount > 0 && dataSize > 0) {
481 size_t size = min_c(sgTable->size, dataSize);
482 phys_addr_t address = sgTable->address;
483 T_PORT(AHCIPortPrdTable(fController, fIndex, address, size));
484 FLOW("FillPrdTable: sg-entry addr %#" B_PRIxPHYSADDR ", size %lu\n",
485 address, size);
486 if (address & 1) {
487 ERROR("AHCIPort::FillPrdTable: data alignment error\n");
488 return B_ERROR;
490 dataSize -= size;
491 while (size > 0) {
492 size_t bytes = min_c(size, PRD_MAX_DATA_LENGTH);
493 if (*prdCount == prdMax) {
494 ERROR("AHCIPort::FillPrdTable: prd table exhausted\n");
495 return B_ERROR;
497 FLOW("FillPrdTable: prd-entry %u, addr %p, size %lu\n",
498 *prdCount, address, bytes);
500 prdTable->dba = LO32(address);
501 prdTable->dbau = HI32(address);
502 prdTable->res = 0;
503 prdTable->dbc = bytes - 1;
504 *prdCount += 1;
505 prdTable++;
506 address = address + bytes;
507 size -= bytes;
509 sgTable++;
510 sgCount--;
512 if (*prdCount == 0) {
513 ERROR("%s: count is 0\n", __func__);
514 return B_ERROR;
516 if (dataSize > 0) {
517 ERROR("AHCIPort::FillPrdTable: sg table %ld bytes too small\n",
518 dataSize);
519 return B_ERROR;
521 return B_OK;
525 void
526 AHCIPort::StartTransfer()
528 acquire_sem(fRequestSem);
532 status_t
533 AHCIPort::WaitForTransfer(int* tfd, bigtime_t timeout)
535 status_t result = acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT,
536 timeout);
537 if (result < B_OK) {
538 cpu_status cpu = disable_interrupts();
539 acquire_spinlock(&fSpinlock);
540 fCommandsActive &= ~1;
541 release_spinlock(&fSpinlock);
542 restore_interrupts(cpu);
544 result = B_TIMED_OUT;
545 } else if (fError) {
546 *tfd = fRegs->tfd;
547 result = B_ERROR;
548 fError = false;
549 } else {
550 *tfd = fRegs->tfd;
552 return result;
556 void
557 AHCIPort::FinishTransfer()
559 release_sem(fRequestSem);
563 void
564 AHCIPort::ScsiTestUnitReady(scsi_ccb* request)
566 TRACE("AHCIPort::ScsiTestUnitReady port %d\n", fIndex);
567 request->subsys_status = SCSI_REQ_CMP;
568 gSCSI->finished(request, 1);
572 void
573 AHCIPort::ScsiVPDInquiry(scsi_ccb* request, ata_device_infoblock* ataData)
575 TRACE("AHCIPort::ScsiVPDInquiry port %d\n", fIndex);
577 const scsi_cmd_inquiry* cmd = (const scsi_cmd_inquiry*)request->cdb;
579 size_t vpdDataLength = 0;
580 status_t transactionResult = B_ERROR;
582 switch (cmd->page_code) {
583 case SCSI_PAGE_SUPPORTED_VPD:
585 scsi_page_list vpdPageData;
586 vpdDataLength = sizeof(vpdPageData);
588 vpdPageData.page_code = cmd->page_code;
589 // Our supported pages
590 vpdPageData.page_length = 1;
591 vpdPageData.pages[0] = SCSI_PAGE_BLOCK_LIMITS;
593 transactionResult = sg_memcpy(request->sg_list, request->sg_count,
594 &vpdPageData, vpdDataLength);
595 break;
597 case SCSI_PAGE_BLOCK_LIMITS:
599 scsi_page_block_limits vpdPageData;
600 vpdDataLength = sizeof(vpdPageData);
602 vpdPageData.page_code = cmd->page_code;
603 vpdPageData.max_unmap_lba_count
604 = ataData->max_data_set_management_lba_range_blocks;
606 transactionResult = sg_memcpy(request->sg_list, request->sg_count,
607 &vpdPageData, vpdDataLength);
608 break;
610 case SCSI_PAGE_USN:
611 case SCSI_PAGE_BLOCK_DEVICE_CHARS:
612 case SCSI_PAGE_LB_PROVISIONING:
613 case SCSI_PAGE_REFERRALS:
614 ERROR("VPD AHCI page %d not yet implemented!\n",
615 cmd->page_code);
616 //request->subsys_status = SCSI_REQ_CMP;
617 request->subsys_status = SCSI_REQ_ABORTED;
618 return;
619 default:
620 ERROR("unknown VPD page code!\n");
621 request->subsys_status = SCSI_REQ_ABORTED;
622 return;
625 if (transactionResult < B_OK) {
626 request->subsys_status = SCSI_DATA_RUN_ERR;
627 } else {
628 request->subsys_status = SCSI_REQ_CMP;
629 request->data_resid = request->data_length
630 - vpdDataLength;
635 void
636 AHCIPort::ScsiInquiry(scsi_ccb* request)
638 TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex);
640 const scsi_cmd_inquiry* cmd = (const scsi_cmd_inquiry*)request->cdb;
641 scsi_res_inquiry scsiData;
642 ata_device_infoblock ataData;
644 ASSERT(sizeof(ataData) == 512);
646 if (cmd->evpd) {
647 TRACE("VPD inquiry page 0x%X\n", cmd->page_code);
648 if (!request->data || request->data_length == 0) {
649 ERROR("invalid VPD request\n");
650 request->subsys_status = SCSI_REQ_ABORTED;
651 gSCSI->finished(request, 1);
652 return;
654 } else if (cmd->page_code) {
655 // page_code without evpd is invalid per SCSI spec
656 ERROR("page code 0x%X on non-VPD request\n", cmd->page_code);
657 request->subsys_status = SCSI_REQ_ABORTED;
658 request->device_status = SCSI_STATUS_CHECK_CONDITION;
659 // TODO: Sense ILLEGAL REQUEST + INVALID FIELD IN CDB?
660 gSCSI->finished(request, 1);
661 return;
662 } else if (request->data_length < sizeof(scsiData)) {
663 ERROR("invalid request\n");
664 request->subsys_status = SCSI_REQ_ABORTED;
665 gSCSI->finished(request, 1);
666 return;
669 sata_request sreq;
670 sreq.SetData(&ataData, sizeof(ataData));
671 sreq.SetATACommand(fIsATAPI
672 ? ATA_COMMAND_IDENTIFY_PACKET_DEVICE : ATA_COMMAND_IDENTIFY_DEVICE);
673 ExecuteSataRequest(&sreq);
674 sreq.WaitForCompletion();
676 if ((sreq.CompletionStatus() & ATA_STATUS_ERROR) != 0) {
677 ERROR("identify device failed\n");
678 request->subsys_status = SCSI_REQ_CMP_ERR;
679 gSCSI->finished(request, 1);
680 return;
683 if (cmd->evpd) {
684 // Simulate SCSI VPD data.
685 ScsiVPDInquiry(request, &ataData);
686 gSCSI->finished(request, 1);
687 return;
691 uint8* data = (uint8*)&ataData;
692 for (int i = 0; i < 512; i += 8) {
693 TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1],
694 data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]);
698 scsiData.device_type = fIsATAPI
699 ? ataData.word_0.atapi.command_packet_set : scsi_dev_direct_access;
700 scsiData.device_qualifier = scsi_periph_qual_connected;
701 scsiData.device_type_modifier = 0;
702 scsiData.removable_medium = ataData.word_0.ata.removable_media_device;
703 scsiData.ansi_version = 2;
704 scsiData.ecma_version = 0;
705 scsiData.iso_version = 0;
706 scsiData.response_data_format = 2;
707 scsiData.term_iop = false;
708 scsiData.additional_length = sizeof(scsi_res_inquiry) - 4;
709 scsiData.soft_reset = false;
710 scsiData.cmd_queue = false;
711 scsiData.linked = false;
712 scsiData.sync = false;
713 scsiData.write_bus16 = true;
714 scsiData.write_bus32 = false;
715 scsiData.relative_address = false;
717 if (!fIsATAPI) {
718 fSectorCount = ataData.SectorCount(fUse48BitCommands, true);
719 fSectorSize = ataData.SectorSize();
720 fTrimSupported = ataData.data_set_management_support;
721 fMaxTrimRangeBlocks = B_LENDIAN_TO_HOST_INT16(
722 ataData.max_data_set_management_lba_range_blocks);
723 TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %" B_PRIu32
724 ", sectors48 %" B_PRIu64 ", size %" B_PRIu64 "\n",
725 ataData.dma_supported != 0, ataData.lba48_supported != 0,
726 fUse48BitCommands, ataData.lba_sector_count,
727 ataData.lba48_sector_count, fSectorCount * fSectorSize);
728 if (fTrimSupported) {
729 if (fMaxTrimRangeBlocks == 0)
730 fMaxTrimRangeBlocks = 1;
732 #ifdef TRACE_AHCI
733 bool deterministic = ataData.supports_deterministic_read_after_trim;
734 TRACE("trim supported, %" B_PRIu32 " ranges blocks, reads are "
735 "%sdeterministic%s.\n", fMaxTrimRangeBlocks,
736 deterministic ? "" : "non-", deterministic
737 ? (ataData.supports_read_zero_after_trim
738 ? ", zero" : ", random") : "");
739 #endif
743 #if 0
744 if (fSectorCount < 0x0fffffff) {
745 TRACE("disabling 48 bit commands\n");
746 fUse48BitCommands = 0;
748 #endif
750 char modelNumber[sizeof(ataData.model_number) + 1];
751 char serialNumber[sizeof(ataData.serial_number) + 1];
752 char firmwareRev[sizeof(ataData.firmware_revision) + 1];
754 strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber));
755 strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber));
756 strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev));
758 swap_words(modelNumber, sizeof(modelNumber) - 1);
759 swap_words(serialNumber, sizeof(serialNumber) - 1);
760 swap_words(firmwareRev, sizeof(firmwareRev) - 1);
762 TRACE("model number: %s\n", modelNumber);
763 TRACE("serial number: %s\n", serialNumber);
764 TRACE("firmware rev.: %s\n", firmwareRev);
766 // There's not enough space to fit all of the data in. ATA has 40 bytes for
767 // the model number, 20 for the serial number and another 8 for the
768 // firmware revision. SCSI has room for 8 for vendor ident, 16 for product
769 // ident and another 4 for product revision.
770 size_t vendorLen = strcspn(modelNumber, " ");
771 if (vendorLen >= sizeof(scsiData.vendor_ident))
772 vendorLen = strcspn(modelNumber, "-");
773 if (vendorLen < sizeof(scsiData.vendor_ident)) {
774 // First we try to break things apart smartly.
775 snprintf(scsiData.vendor_ident, vendorLen + 1, "%s", modelNumber);
776 size_t modelRemain = (sizeof(modelNumber) - vendorLen);
777 if (modelRemain > sizeof(scsiData.product_ident))
778 modelRemain = sizeof(scsiData.product_ident);
779 memcpy(scsiData.product_ident, modelNumber + (vendorLen + 1),
780 modelRemain);
781 } else {
782 // If we're unable to smartly break apart the vendor and model, just
783 // dumbly squeeze as much in as possible.
784 memcpy(scsiData.vendor_ident, modelNumber, sizeof(scsiData.vendor_ident));
785 memcpy(scsiData.product_ident, modelNumber + 8,
786 sizeof(scsiData.product_ident));
788 // Take the last 4 digits of the serial number as product rev
789 size_t serialLen = sizeof(scsiData.product_rev);
790 size_t serialOff = sizeof(serialNumber) - serialLen;
791 memcpy(scsiData.product_rev, serialNumber + serialOff, serialLen);
793 if (sg_memcpy(request->sg_list, request->sg_count, &scsiData,
794 sizeof(scsiData)) < B_OK) {
795 request->subsys_status = SCSI_DATA_RUN_ERR;
796 } else {
797 request->subsys_status = SCSI_REQ_CMP;
798 request->data_resid = request->data_length - sizeof(scsiData);
800 gSCSI->finished(request, 1);
804 void
805 AHCIPort::ScsiSynchronizeCache(scsi_ccb* request)
807 //TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex);
809 sata_request* sreq = new(std::nothrow) sata_request(request);
810 if (sreq == NULL) {
811 ERROR("out of memory when allocating sync request\n");
812 request->subsys_status = SCSI_REQ_ABORTED;
813 gSCSI->finished(request, 1);
814 return;
817 sreq->SetATACommand(fUse48BitCommands
818 ? ATA_COMMAND_FLUSH_CACHE_EXT : ATA_COMMAND_FLUSH_CACHE);
819 ExecuteSataRequest(sreq);
823 void
824 AHCIPort::ScsiReadCapacity(scsi_ccb* request)
826 TRACE("AHCIPort::ScsiReadCapacity port %d\n", fIndex);
828 const scsi_cmd_read_capacity* cmd
829 = (const scsi_cmd_read_capacity*)request->cdb;
830 scsi_res_read_capacity scsiData;
832 if (cmd->pmi || cmd->lba || request->data_length < sizeof(scsiData)) {
833 TRACE("invalid request\n");
834 request->subsys_status = SCSI_REQ_ABORTED;
835 gSCSI->finished(request, 1);
836 return;
839 TRACE("SectorSize %" B_PRIu32 ", SectorCount 0x%" B_PRIx64 "\n",
840 fSectorSize, fSectorCount);
842 scsiData.block_size = B_HOST_TO_BENDIAN_INT32(fSectorSize);
844 if (fSectorCount <= 0xffffffff)
845 scsiData.lba = B_HOST_TO_BENDIAN_INT32(fSectorCount - 1);
846 else
847 scsiData.lba = 0xffffffff;
849 if (sg_memcpy(request->sg_list, request->sg_count, &scsiData,
850 sizeof(scsiData)) < B_OK) {
851 request->subsys_status = SCSI_DATA_RUN_ERR;
852 } else {
853 request->subsys_status = SCSI_REQ_CMP;
854 request->data_resid = request->data_length - sizeof(scsiData);
856 gSCSI->finished(request, 1);
860 void
861 AHCIPort::ScsiReadCapacity16(scsi_ccb* request)
863 TRACE("AHCIPort::ScsiReadCapacity16 port %d\n", fIndex);
865 scsi_res_read_capacity_long scsiData;
867 TRACE("SectorSize %" B_PRIu32 ", SectorCount 0x%" B_PRIx64 "\n",
868 fSectorSize, fSectorCount);
870 scsiData.block_size = B_HOST_TO_BENDIAN_INT32(fSectorSize);
871 scsiData.lba = B_HOST_TO_BENDIAN_INT64(fSectorCount - 1);
873 if (sg_memcpy(request->sg_list, request->sg_count, &scsiData,
874 sizeof(scsiData)) < B_OK) {
875 request->subsys_status = SCSI_DATA_RUN_ERR;
876 } else {
877 request->subsys_status = SCSI_REQ_CMP;
878 request->data_resid = request->data_length - sizeof(scsiData);
880 gSCSI->finished(request, 1);
884 void
885 AHCIPort::ScsiReadWrite(scsi_ccb* request, uint64 lba, size_t sectorCount,
886 bool isWrite)
888 RWTRACE("[%lld] %ld ScsiReadWrite: position %llu, size %lu, isWrite %d\n",
889 system_time(), find_thread(NULL), lba * 512, sectorCount * 512,
890 isWrite);
892 #if 0
893 if (isWrite) {
894 TRACE("write request ignored\n");
895 request->subsys_status = SCSI_REQ_CMP;
896 request->data_resid = 0;
897 gSCSI->finished(request, 1);
898 return;
900 #endif
902 ASSERT(request->data_length == sectorCount * 512);
903 sata_request* sreq = new(std::nothrow) sata_request(request);
904 if (sreq == NULL) {
905 TRACE("out of memory when allocating read/write request\n");
906 request->subsys_status = SCSI_REQ_ABORTED;
907 gSCSI->finished(request, 1);
908 return;
911 if (fUse48BitCommands) {
912 if (sectorCount > 65536) {
913 panic("ahci: ScsiReadWrite length too large, %lu sectors",
914 sectorCount);
916 if (lba > MAX_SECTOR_LBA_48)
917 panic("achi: ScsiReadWrite position too large for 48-bit LBA\n");
918 sreq->SetATA48Command(
919 isWrite ? ATA_COMMAND_WRITE_DMA_EXT : ATA_COMMAND_READ_DMA_EXT,
920 lba, sectorCount);
921 } else {
922 if (sectorCount > 256) {
923 panic("ahci: ScsiReadWrite length too large, %lu sectors",
924 sectorCount);
926 if (lba > MAX_SECTOR_LBA_28)
927 panic("achi: ScsiReadWrite position too large for normal LBA\n");
928 sreq->SetATA28Command(isWrite
929 ? ATA_COMMAND_WRITE_DMA : ATA_COMMAND_READ_DMA, lba, sectorCount);
932 ExecuteSataRequest(sreq, isWrite);
936 void
937 AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks)
939 // Determine how many blocks are supposed to be trimmed in total
940 uint32 scsiRangeCount = B_BENDIAN_TO_HOST_INT16(
941 unmapBlocks->block_data_length) / sizeof(scsi_unmap_block_descriptor);
943 dprintf("TRIM SCSI:\n");
944 for (uint32 i = 0; i < scsiRangeCount; i++) {
945 dprintf("[%3" B_PRIu32 "] %" B_PRIu64 " : %" B_PRIu32 "\n", i,
946 (uint64)B_BENDIAN_TO_HOST_INT64(unmapBlocks->blocks[i].lba),
947 (uint32)B_BENDIAN_TO_HOST_INT32(unmapBlocks->blocks[i].block_count));
950 uint32 scsiIndex = 0;
951 uint32 scsiLastBlocks = 0;
952 uint32 maxLBARangeCount = fMaxTrimRangeBlocks * 512 / 8;
953 // 512 bytes per range block, 8 bytes per range
955 // Split the SCSI ranges into ATA ranges as large as allowed.
956 // We assume that the SCSI unmap ranges cannot be merged together
958 while (scsiIndex < scsiRangeCount) {
959 // Determine how many LBA ranges we need for the next chunk
960 uint32 lbaRangeCount = 0;
961 for (uint32 i = scsiIndex; i < scsiRangeCount; i++) {
962 uint32 scsiBlocks = B_BENDIAN_TO_HOST_INT32(
963 unmapBlocks->blocks[i].block_count);
964 if (scsiBlocks == 0)
965 break;
966 if (i == scsiIndex)
967 scsiBlocks -= scsiLastBlocks;
969 lbaRangeCount += (scsiBlocks + 65534) / 65535;
970 if (lbaRangeCount >= maxLBARangeCount) {
971 lbaRangeCount = maxLBARangeCount;
972 break;
975 if (lbaRangeCount == 0)
976 break;
978 uint32 lbaRangesSize = lbaRangeCount * sizeof(uint64);
979 uint64* lbaRanges = (uint64*)malloc(lbaRangesSize);
980 if (lbaRanges == NULL) {
981 ERROR("out of memory when allocating %" B_PRIu32 " unmap ranges\n",
982 lbaRangeCount);
983 request->subsys_status = SCSI_REQ_ABORTED;
984 gSCSI->finished(request, 1);
985 return;
988 MemoryDeleter deleter(lbaRanges);
990 for (uint32 lbaIndex = 0;
991 scsiIndex < scsiRangeCount && lbaIndex < lbaRangeCount;) {
992 uint64 scsiOffset = B_BENDIAN_TO_HOST_INT64(
993 unmapBlocks->blocks[scsiIndex].lba) + scsiLastBlocks;
994 uint32 scsiBlocksLeft = B_BENDIAN_TO_HOST_INT32(
995 unmapBlocks->blocks[scsiIndex].block_count) - scsiLastBlocks;
997 if (scsiBlocksLeft == 0) {
998 // Ignore the rest of the ranges (they are empty)
999 scsiIndex = scsiRangeCount;
1000 break;
1003 while (scsiBlocksLeft > 0 && lbaIndex < lbaRangeCount) {
1004 uint16 blocks = scsiBlocksLeft > 65535
1005 ? 65535 : (uint16)scsiBlocksLeft;
1006 lbaRanges[lbaIndex++] = B_HOST_TO_LENDIAN_INT64(
1007 ((uint64)blocks << 48) | scsiOffset);
1009 scsiOffset += blocks;
1010 scsiLastBlocks += blocks;
1011 scsiBlocksLeft -= blocks;
1014 if (scsiBlocksLeft == 0) {
1015 scsiLastBlocks = 0;
1016 scsiIndex++;
1020 dprintf("TRIM AHCI:\n");
1021 for (uint32 i = 0; i < lbaRangeCount; i++) {
1022 uint64 value = B_HOST_TO_LENDIAN_INT64(lbaRanges[i]);
1023 dprintf("[%3" B_PRIu32 "] %" B_PRIu64 " : %" B_PRIu64 "\n", i,
1024 value & (((uint64)1 << 48) - 1), value >> 48);
1027 sata_request sreq;
1028 sreq.SetATA48Command(ATA_COMMAND_DATA_SET_MANAGEMENT, 0,
1029 (lbaRangesSize + 511) / 512);
1030 sreq.SetFeature(1);
1031 sreq.SetData(lbaRanges, lbaRangesSize);
1033 ExecuteSataRequest(&sreq);
1034 sreq.WaitForCompletion();
1036 if ((sreq.CompletionStatus() & ATA_STATUS_ERROR) != 0) {
1037 ERROR("trim failed (%" B_PRIu32 " ranges)!\n", lbaRangeCount);
1038 request->subsys_status = SCSI_REQ_CMP_ERR;
1039 } else
1040 request->subsys_status = SCSI_REQ_CMP;
1043 request->data_resid = 0;
1044 request->device_status = SCSI_STATUS_GOOD;
1045 gSCSI->finished(request, 1);
1049 void
1050 AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite)
1052 FLOW("ExecuteAtaRequest port %d\n", fIndex);
1054 StartTransfer();
1056 int prdEntrys;
1058 if (request->CCB() && request->CCB()->data_length) {
1059 FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT,
1060 request->CCB()->sg_list, request->CCB()->sg_count,
1061 request->CCB()->data_length);
1062 } else if (request->Data() && request->Size()) {
1063 FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT,
1064 request->Data(), request->Size());
1065 } else
1066 prdEntrys = 0;
1068 FLOW("prdEntrys %d\n", prdEntrys);
1070 fCommandList->prdtl_flags_cfl = 0;
1071 fCommandList->cfl = 5; // 20 bytes, length in DWORDS
1072 memcpy((char*)fCommandTable->cfis, request->FIS(), 20);
1074 // We some hide messages when the test unit ready active is clear
1075 // as empty removeable media resets constantly.
1076 fTestUnitReadyActive = request->IsTestUnitReady();
1078 if (request->IsATAPI()) {
1079 // ATAPI PACKET is a 12 or 16 byte SCSI command
1080 memset((char*)fCommandTable->acmd, 0, 32);
1081 memcpy((char*)fCommandTable->acmd, request->CCB()->cdb,
1082 request->CCB()->cdb_length);
1083 fCommandList->a = 1;
1086 if (isWrite)
1087 fCommandList->w = 1;
1088 fCommandList->prdtl = prdEntrys;
1089 fCommandList->prdbc = 0;
1091 if (wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST,
1092 1000000) < B_OK) {
1093 ERROR("ExecuteAtaRequest port %d: device is busy\n", fIndex);
1094 PortReset();
1095 FinishTransfer();
1096 request->Abort();
1097 return;
1100 cpu_status cpu = disable_interrupts();
1101 acquire_spinlock(&fSpinlock);
1102 fCommandsActive |= 1;
1103 fRegs->ci = 1;
1104 FlushPostedWrites();
1105 release_spinlock(&fSpinlock);
1106 restore_interrupts(cpu);
1108 int tfd;
1109 status_t status = WaitForTransfer(&tfd, 20000000);
1111 FLOW("Port %d sata request flow:\n", fIndex);
1112 FLOW(" tfd %#x\n", tfd);
1113 FLOW(" prdbc %ld\n", fCommandList->prdbc);
1114 FLOW(" ci 0x%08" B_PRIx32 "\n", fRegs->ci);
1115 FLOW(" is 0x%08" B_PRIx32 "\n", fRegs->is);
1116 FLOW(" serr 0x%08" B_PRIx32 "\n", fRegs->serr);
1119 TRACE("ci 0x%08" B_PRIx32 "\n", fRegs->ci);
1120 TRACE("ie 0x%08" B_PRIx32 "\n", fRegs->ie);
1121 TRACE("is 0x%08" B_PRIx32 "\n", fRegs->is);
1122 TRACE("cmd 0x%08" B_PRIx32 "\n", fRegs->cmd);
1123 TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts);
1124 TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl);
1125 TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr);
1126 TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact);
1127 TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd);
1130 if (fPortReset || status == B_TIMED_OUT) {
1131 fPortReset = false;
1132 PortReset();
1135 size_t bytesTransfered = fCommandList->prdbc;
1137 FinishTransfer();
1139 if (status == B_TIMED_OUT) {
1140 ERROR("ExecuteAtaRequest port %d: device timeout\n", fIndex);
1141 request->Abort();
1142 return;
1145 request->Finish(tfd, bytesTransfered);
1149 void
1150 AHCIPort::ScsiExecuteRequest(scsi_ccb* request)
1152 // TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
1154 if (fIsATAPI) {
1155 bool isWrite = false;
1156 switch (request->flags & SCSI_DIR_MASK) {
1157 case SCSI_DIR_NONE:
1158 ASSERT(request->data_length == 0);
1159 break;
1160 case SCSI_DIR_IN:
1161 ASSERT(request->data_length > 0);
1162 break;
1163 case SCSI_DIR_OUT:
1164 isWrite = true;
1165 ASSERT(request->data_length > 0);
1166 break;
1167 default:
1168 panic("CDB has invalid direction mask");
1171 // TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
1173 sata_request* sreq = new(std::nothrow) sata_request(request);
1174 if (sreq == NULL) {
1175 ERROR("out of memory when allocating atapi request\n");
1176 request->subsys_status = SCSI_REQ_ABORTED;
1177 gSCSI->finished(request, 1);
1178 return;
1181 sreq->SetATAPICommand(request->data_length);
1182 // uint8* data = (uint8*) sreq->ccb()->cdb;
1183 // for (int i = 0; i < 16; i += 8) {
1184 // 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]);
1185 // }
1186 ExecuteSataRequest(sreq, isWrite);
1187 return;
1190 if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) {
1191 panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");
1192 return;
1195 if (!fDevicePresent) {
1196 TRACE("no device present on port %d\n", fIndex);
1197 request->subsys_status = SCSI_DEV_NOT_THERE;
1198 gSCSI->finished(request, 1);
1199 return;
1202 request->subsys_status = SCSI_REQ_CMP;
1204 switch (request->cdb[0]) {
1205 case SCSI_OP_TEST_UNIT_READY:
1206 ScsiTestUnitReady(request);
1207 break;
1208 case SCSI_OP_INQUIRY:
1209 ScsiInquiry(request);
1210 break;
1211 case SCSI_OP_READ_CAPACITY:
1212 ScsiReadCapacity(request);
1213 break;
1214 case SCSI_OP_SERVICE_ACTION_IN:
1215 if ((request->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16)
1216 ScsiReadCapacity16(request);
1217 else {
1218 request->subsys_status = SCSI_REQ_INVALID;
1219 gSCSI->finished(request, 1);
1221 break;
1222 case SCSI_OP_SYNCHRONIZE_CACHE:
1223 ScsiSynchronizeCache(request);
1224 break;
1225 case SCSI_OP_READ_6:
1226 case SCSI_OP_WRITE_6:
1228 const scsi_cmd_rw_6* cmd = (const scsi_cmd_rw_6*)request->cdb;
1229 uint32 position = ((uint32)cmd->high_lba << 16)
1230 | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba;
1231 size_t length = cmd->length != 0 ? cmd->length : 256;
1232 bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6;
1233 ScsiReadWrite(request, position, length, isWrite);
1234 break;
1236 case SCSI_OP_READ_10:
1237 case SCSI_OP_WRITE_10:
1239 const scsi_cmd_rw_10* cmd = (const scsi_cmd_rw_10*)request->cdb;
1240 uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
1241 size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length);
1242 bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10;
1243 if (length) {
1244 ScsiReadWrite(request, position, length, isWrite);
1245 } else {
1246 ERROR("AHCIPort::ScsiExecuteRequest error: transfer without "
1247 "data!\n");
1248 request->subsys_status = SCSI_REQ_INVALID;
1249 gSCSI->finished(request, 1);
1251 break;
1253 case SCSI_OP_READ_12:
1254 case SCSI_OP_WRITE_12:
1256 const scsi_cmd_rw_12* cmd = (const scsi_cmd_rw_12*)request->cdb;
1257 uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
1258 size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
1259 bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12;
1260 if (length) {
1261 ScsiReadWrite(request, position, length, isWrite);
1262 } else {
1263 ERROR("AHCIPort::ScsiExecuteRequest error: transfer without "
1264 "data!\n");
1265 request->subsys_status = SCSI_REQ_INVALID;
1266 gSCSI->finished(request, 1);
1268 break;
1270 case SCSI_OP_READ_16:
1271 case SCSI_OP_WRITE_16:
1273 const scsi_cmd_rw_16* cmd = (const scsi_cmd_rw_16*)request->cdb;
1274 uint64 position = B_BENDIAN_TO_HOST_INT64(cmd->lba);
1275 size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
1276 bool isWrite = request->cdb[0] == SCSI_OP_WRITE_16;
1277 if (length) {
1278 ScsiReadWrite(request, position, length, isWrite);
1279 } else {
1280 ERROR("AHCIPort::ScsiExecuteRequest error: transfer without "
1281 "data!\n");
1282 request->subsys_status = SCSI_REQ_INVALID;
1283 gSCSI->finished(request, 1);
1285 break;
1287 case SCSI_OP_UNMAP:
1289 const scsi_cmd_unmap* cmd = (const scsi_cmd_unmap*)request->cdb;
1291 if (!fTrimSupported) {
1292 ERROR("%s port %d: unsupported request opcode 0x%02x\n",
1293 __func__, fIndex, request->cdb[0]);
1294 request->subsys_status = SCSI_REQ_ABORTED;
1295 gSCSI->finished(request, 1);
1296 break;
1299 scsi_unmap_parameter_list* unmapBlocks
1300 = (scsi_unmap_parameter_list*)request->data;
1301 if (unmapBlocks == NULL
1302 || B_BENDIAN_TO_HOST_INT16(cmd->length) != request->data_length
1303 || B_BENDIAN_TO_HOST_INT16(unmapBlocks->data_length)
1304 != request->data_length - 1) {
1305 ERROR("%s port %d: invalid unmap parameter data length\n",
1306 __func__, fIndex);
1307 request->subsys_status = SCSI_REQ_ABORTED;
1308 gSCSI->finished(request, 1);
1309 } else {
1310 ScsiUnmap(request, unmapBlocks);
1312 break;
1314 default:
1315 ERROR("AHCIPort::ScsiExecuteRequest port %d unsupported request "
1316 "opcode 0x%02x\n", fIndex, request->cdb[0]);
1317 request->subsys_status = SCSI_REQ_ABORTED;
1318 gSCSI->finished(request, 1);
1323 uchar
1324 AHCIPort::ScsiAbortRequest(scsi_ccb* request)
1326 return SCSI_REQ_CMP;
1330 uchar
1331 AHCIPort::ScsiTerminateRequest(scsi_ccb* request)
1333 return SCSI_REQ_CMP;
1337 uchar
1338 AHCIPort::ScsiResetDevice()
1340 return SCSI_REQ_CMP;
1344 void
1345 AHCIPort::ScsiGetRestrictions(bool* isATAPI, bool* noAutoSense,
1346 uint32* maxBlocks)
1348 *isATAPI = fIsATAPI;
1349 *noAutoSense = fIsATAPI; // emulated auto sense for ATA, but not ATAPI
1350 *maxBlocks = fUse48BitCommands ? 65536 : 256;
1351 TRACE("AHCIPort::ScsiGetRestrictions port %d: isATAPI %d, noAutoSense %d, "
1352 "maxBlocks %" B_PRIu32 "\n", fIndex, *isATAPI, *noAutoSense,
1353 *maxBlocks);
1357 bool
1358 AHCIPort::Enable()
1360 // Spec v1.3.1, §10.3.1 Start (PxCMD.ST)
1361 TRACE("%s: port %d\n", __func__, fIndex);
1363 if ((fRegs->cmd & PORT_CMD_ST) != 0) {
1364 ERROR("%s: Starting port already running!\n", __func__);
1365 return false;
1368 if ((fRegs->cmd & PORT_CMD_FRE) == 0) {
1369 ERROR("%s: Unable to start port without FRE enabled!\n", __func__);
1370 return false;
1373 // Clear DMA engine and wait for completion
1374 if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
1375 ERROR("%s: port %d error DMA engine still running\n", __func__,
1376 fIndex);
1377 return false;
1379 // Start port
1380 fRegs->cmd |= PORT_CMD_ST;
1381 FlushPostedWrites();
1382 return true;
1386 bool
1387 AHCIPort::Disable()
1389 TRACE("%s: port %d\n", __func__, fIndex);
1391 if ((fRegs->cmd & PORT_CMD_ST) == 0) {
1392 // Port already disabled, carry on.
1393 TRACE("%s: port %d attempting to disable stopped port.\n",
1394 __func__, fIndex);
1395 } else {
1396 // Disable port
1397 fRegs->cmd &= ~PORT_CMD_ST;
1398 FlushPostedWrites();
1401 // Spec v1.3.1, §10.4.2 Port Reset - assume hung after 500 mil.
1402 // Clear DMA engine and wait for completion
1403 if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
1404 ERROR("%s: port %d error DMA engine still running\n", __func__,
1405 fIndex);
1406 return false;
1409 return true;
1413 void
1414 AHCIPort::_ClearErrorRegister()
1416 // clear error bits
1417 fRegs->serr = fRegs->serr;
1418 FlushPostedWrites();