Implemented ExecuteSataRequest() to execute all ATA and (later) ATAPI commands.

Converted Identify Device and Read / Write commands, they now create a sata_request
and pass it to ExecuteSataRequest. Added support for cache flushing.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23250 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen
2008-01-05 02:27:05 +00:00
parent 56f0b1a01a
commit ec2bf719e8
5 changed files with 99 additions and 112 deletions
@@ -8,5 +8,6 @@ KernelAddon ahci :
ahci_controller.cpp
ahci_port.cpp
ahci_sim.cpp
sata_request.cpp
util.c
;
+3 -2
View File
@@ -17,8 +17,6 @@
#define AHCI_ID_GENERATOR "ahci/id"
#define AHCI_ID_ITEM "ahci/id"
device_manager_info *gDeviceManager;
const device_info kSupportedDevices[] = {
{ 0x1002, 0x4380, "ATI SB600" },
@@ -372,12 +370,15 @@ driver_module_info sAHCIDevice = {
ahci_get_supported_paths,
};
module_dependency module_dependencies[] = {
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
// { B_PCI_MODULE_NAME, (module_info **)&gPCI },
{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&gSCSI },
{}
};
module_info *modules[] = {
(module_info *)&sAHCIDevice,
(module_info *)&gAHCISimInterface,
+90 -110
View File
@@ -8,6 +8,7 @@
#include "util.h"
#include "ata_cmds.h"
#include "scsi_cmds.h"
#include "sata_request.h"
#include <KernelExport.h>
#include <ByteOrder.h>
@@ -15,9 +16,9 @@
#include <string.h>
#define TRACE(a...) dprintf("\33[34mahci:\33[0m " a)
// #define FLOW(a...) dprintf("ahci: " a)
#define FLOW(a...)
//#define FLOW(a...) dprintf("ahci: " a)
//#define RWTRACE(a...) dprintf("\33[34mahci:\33[0m " a)
#define FLOW(a...)
#define RWTRACE(a...)
@@ -400,9 +401,10 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex);
scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)request->cdb;
scsi_res_inquiry scsiData;
ata_res_identify_device ataData;
ASSERT(sizeof(ataData) == 512);
if (cmd->evpd || cmd->page_code) {
TRACE("invalid request\n");
request->subsys_status = SCSI_REQ_ABORTED;
@@ -410,67 +412,27 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
return;
}
memset(&ataData, 0, sizeof(ataData));
sata_request sreq;
sreq.set_data(&ataData, sizeof(ataData));
sreq.set_ata_cmd(0xec); // Identify Device
ExecuteSataRequest(&sreq);
sreq.wait_for_completition();
StartTransfer();
int prdEntrys;
FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, &ataData, sizeof(ataData));
FLOW("prdEntrys %d\n", prdEntrys);
memset((void *)fCommandTable->cfis, 0, 5 * 4);
fCommandTable->cfis[0] = 0x27;
fCommandTable->cfis[1] = 0x80;
fCommandTable->cfis[2] = 0xec;
fCommandList->prdtl_flags_cfl = 0;
fCommandList->prdtl = prdEntrys;
fCommandList->cfl = 5;
fCommandList->prdbc = 0;
if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 4000000) < B_OK) {
TRACE("device is busy\n");
FinishTransfer();
request->subsys_status = SCSI_REQ_ABORTED;
if (sreq.completition_status() & ATA_ERR) {
TRACE("identify device failed\n");
request->subsys_status = SCSI_REQ_CMP_ERR;
gSCSI->finished(request, 1);
return;
}
cpu_status cpu = disable_interrupts();
acquire_spinlock(&fSpinlock);
fRegs->ci |= 1;
FlushPostedWrites();
fCommandsActive |= 1;
release_spinlock(&fSpinlock);
restore_interrupts(cpu);
int status;
WaitForTransfer(&status, 100000);
FLOW("prdbc %ld\n", fCommandList->prdbc);
FLOW("ci 0x%08lx\n", fRegs->ci);
FLOW("is 0x%08lx\n", fRegs->is);
FLOW("serr 0x%08lx\n", fRegs->serr);
/*
TRACE("ci 0x%08lx\n", fRegs->ci);
TRACE("ie 0x%08lx\n", fRegs->ie);
TRACE("is 0x%08lx\n", fRegs->is);
TRACE("cmd 0x%08lx\n", fRegs->cmd);
TRACE("ssts 0x%08lx\n", fRegs->ssts);
TRACE("sctl 0x%08lx\n", fRegs->sctl);
TRACE("serr 0x%08lx\n", fRegs->serr);
TRACE("sact 0x%08lx\n", fRegs->sact);
TRACE("tfd 0x%08lx\n", fRegs->tfd);
uint8 *data = (uint8*) &ataData;
for (int i = 0; i < 512; i += 8) {
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]);
}
*/
scsi_res_inquiry scsiData;
scsiData.device_type = scsi_dev_direct_access;
scsiData.device_qualifier = scsi_periph_qual_connected;
scsiData.device_type_modifier = 0;
@@ -532,13 +494,21 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
request->data_resid = request->data_length - sizeof(scsiData);// ???
request->data_length = sizeof(scsiData); // ???
}
FinishTransfer();
gSCSI->finished(request, 1);
}
void
AHCIPort::ScsiSynchronizeCache(scsi_ccb *request)
{
TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex);
sata_request *sreq = new sata_request(request);
sreq->set_ata_cmd(fUse48BitCommands ? 0xea : 0xe7); // Flush Cache
ExecuteSataRequest(sreq);
}
void
AHCIPort::ScsiReadCapacity(scsi_ccb *request)
{
@@ -575,7 +545,6 @@ void
AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool isWrite)
{
uint32 bytecount = length * 512;
RWTRACE("ScsiReadWrite: position %llu, size %lu, isWrite %d\n", position * 512, bytecount, isWrite);
#if 0
@@ -587,60 +556,61 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool
return;
}
#endif
StartTransfer();
int prdEntrys;
FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->sg_list, request->sg_count, bytecount);
FLOW("prdEntrys %d\n", prdEntrys);
memset((void *)fCommandTable->cfis, 0, 5 * 4);
request->data_length = bytecount; // XXX really?
sata_request *sreq = new sata_request(request);
if (fUse48BitCommands) {
if (length > 65536)
panic("ahci: ScsiReadWrite length too large, %lu sectors", length);
fCommandTable->cfis[0] = 0x27;
fCommandTable->cfis[1] = 0x80;
fCommandTable->cfis[2] = isWrite ? 0x35 : 0x25;
fCommandTable->cfis[4] = position & 0xff;
fCommandTable->cfis[5] = (position >> 8) & 0xff;
fCommandTable->cfis[6] = (position >> 16) & 0xff;
fCommandTable->cfis[7] = 0x40;
fCommandTable->cfis[8] = (position >> 24) & 0xff;
fCommandTable->cfis[9] = (position >> 32) & 0xff;
fCommandTable->cfis[10] = (position >> 40) & 0xff;
fCommandTable->cfis[12] = length & 0xff;
fCommandTable->cfis[13] = (length >> 8) & 0xff;
if (position > MAX_SECTOR_LBA_48)
panic("achi: ScsiReadWrite position too large for 48-bit LBA\n");
sreq->set_ata48_cmd(isWrite ? 0x35 : 0x25, position, length);
} else {
if (length > 256)
panic("ahci: ScsiReadWrite length too large, %lu sectors", length);
if (position > 0x0fffffff)
panic("achi: ScsiReadWrite position too large for non-48-bit LBA\n");
fCommandTable->cfis[0] = 0x27;
fCommandTable->cfis[1] = 0x80;
fCommandTable->cfis[2] = isWrite ? 0xca : 0xc8;
fCommandTable->cfis[4] = position & 0xff;
fCommandTable->cfis[5] = (position >> 8) & 0xff;
fCommandTable->cfis[6] = (position >> 16) & 0xff;
fCommandTable->cfis[7] = 0x40 | ((position >> 24) & 0x0f);
fCommandTable->cfis[12] = length & 0xff;
if (position > MAX_SECTOR_LBA_28)
panic("achi: ScsiReadWrite position too large for normal LBA\n");
sreq->set_ata28_cmd(isWrite ? 0xca : 0xc8, position, length);
}
ExecuteSataRequest(sreq, isWrite);
}
void
AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite)
{
FLOW("ExecuteAtaRequest port %d\n", fIndex);
StartTransfer();
int prdEntrys;
if (request->ccb())
FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->ccb()->sg_list, request->ccb()->sg_count, request->ccb()->data_length);
else if (request->data() && request->size())
FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->data(), request->size());
else
prdEntrys = 0;
FLOW("prdEntrys %d\n", prdEntrys);
memcpy((char *)fCommandTable->cfis, request->fis(), 20);
fCommandList->prdtl_flags_cfl = 0;
fCommandList->prdtl = prdEntrys;
fCommandList->cfl = 5;
fCommandList->cfl = 5; // length is 20 bytes, in DWORDS
if (isWrite)
fCommandList->w = 1;
fCommandList->prdtl = prdEntrys;
fCommandList->prdbc = 0;
if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 4000000) < B_OK) {
TRACE("device is busy\n");
if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 1000000) < B_OK) {
TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex);
FinishTransfer();
request->subsys_status = SCSI_REQ_ABORTED;
gSCSI->finished(request, 1);
request->abort();
return;
}
cpu_status cpu = disable_interrupts();
acquire_spinlock(&fSpinlock);
fRegs->ci |= 1;
@@ -650,28 +620,35 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool
restore_interrupts(cpu);
int tfd;
status_t status = WaitForTransfer(&tfd, 4000000);
status_t status = WaitForTransfer(&tfd, 5000000);
FLOW("tfd %#x\n", tfd);
FLOW("prdbc %ld\n", fCommandList->prdbc);
FLOW("ci 0x%08lx\n", fRegs->ci);
FLOW("is 0x%08lx\n", fRegs->is);
FLOW("serr 0x%08lx\n", fRegs->serr);
if (status < B_OK) {
TRACE("ScsiReadWrite port %d: device timeout\n", fIndex);
request->subsys_status = SCSI_REQ_ABORTED;
} else if (tfd & ATA_ERR) {
TRACE("ScsiReadWrite port %d: device error\n", fIndex);
request->subsys_status = SCSI_REQ_ABORTED;
} else if (fCommandList->prdbc != bytecount) {
TRACE("ScsiReadWrite port %d: should never happen\n", fIndex);
request->subsys_status = SCSI_REQ_CMP_ERR;
} else {
request->subsys_status = SCSI_REQ_CMP;
}
request->data_resid = request->data_length - fCommandList->prdbc;// ???
request->data_length = fCommandList->prdbc; // ???
/*
TRACE("ci 0x%08lx\n", fRegs->ci);
TRACE("ie 0x%08lx\n", fRegs->ie);
TRACE("is 0x%08lx\n", fRegs->is);
TRACE("cmd 0x%08lx\n", fRegs->cmd);
TRACE("ssts 0x%08lx\n", fRegs->ssts);
TRACE("sctl 0x%08lx\n", fRegs->sctl);
TRACE("serr 0x%08lx\n", fRegs->serr);
TRACE("sact 0x%08lx\n", fRegs->sact);
TRACE("tfd 0x%08lx\n", fRegs->tfd);
*/
size_t bytesTransfered = fCommandList->prdbc;
FinishTransfer();
gSCSI->finished(request, 1);
if (status < B_OK) {
TRACE("ExecuteAtaRequest port %d: device transfer timeout\n", fIndex);
request->abort();
} else
request->finish(tfd, bytesTransfered);
}
@@ -687,7 +664,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
}
if (!fDevicePresent) {
TRACE("no such device!\n");
TRACE("no device present on port %d\n", fIndex);
request->subsys_status = SCSI_DEV_NOT_THERE;
gSCSI->finished(request, 1);
return;
@@ -705,6 +682,9 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
case SCSI_OP_READ_CAPACITY:
ScsiReadCapacity(request);
break;
case SCSI_OP_SYNCHRONIZE_CACHE:
ScsiSynchronizeCache(request);
break;
case SCSI_OP_READ_6:
case SCSI_OP_WRITE_6:
{
@@ -8,6 +8,7 @@
#include "ahci_defs.h"
class AHCIController;
class sata_request;
class AHCIPort {
public:
@@ -32,6 +33,9 @@ private:
void ScsiInquiry(scsi_ccb *request);
void ScsiReadCapacity(scsi_ccb *request);
void ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool isWrite);
void ScsiSynchronizeCache(scsi_ccb *request);
void ExecuteSataRequest(sata_request *request, bool isWrite = false);
status_t ResetDevice();
status_t PostResetDevice();
@@ -15,6 +15,7 @@
pci_device_module_info *gPCI;
device_manager_info *gDeviceManager;
scsi_for_sim_interface *gSCSI;