1/* 2 * Copyright 2008, Marcus Overhagen. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include <string.h> 8 9#include "sata_request.h" 10#include "scsi_cmds.h" 11 12 13#define FIS_TYPE_REGISTER_HOST_TO_DEVICE 0x27 14 15 16sata_request::sata_request() 17 : 18 fCcb(NULL), 19 fIsATAPI(false), 20 fCompletionSem(create_sem(0, "sata completion")), 21 fCompletionStatus(0), 22 fData(NULL), 23 fDataSize(0) 24{ 25} 26 27 28sata_request::sata_request(scsi_ccb* ccb) 29 : 30 fCcb(ccb), 31 fIsATAPI(false), 32 fCompletionSem(-1), 33 fCompletionStatus(0), 34 fData(NULL), 35 fDataSize(0) 36{ 37} 38 39 40sata_request::~sata_request() 41{ 42 if (fCompletionSem >= 0) 43 delete_sem(fCompletionSem); 44} 45 46 47void 48sata_request::SetData(void* data, size_t dataSize) 49{ 50 ASSERT(fCcb == NULL); 51 fData = data; 52 fDataSize = dataSize; 53} 54 55 56void 57sata_request::SetATACommand(uint8 command) 58{ 59 memset(fFis, 0, sizeof(fFis)); 60 fFis[0] = FIS_TYPE_REGISTER_HOST_TO_DEVICE; 61 fFis[1] = 0x80; 62 // This is a command 63 fFis[2] = command; 64} 65 66 67void 68sata_request::SetATA28Command(uint8 command, uint32 lba, uint8 sectorCount) 69{ 70 SetATACommand(command); 71 fFis[4] = lba & 0xff; 72 fFis[5] = (lba >> 8) & 0xff; 73 fFis[6] = (lba >> 16) & 0xff; 74 fFis[7] = 0x40 | ((lba >> 24) & 0x0f); 75 // device 76 fFis[12] = sectorCount & 0xff; 77} 78 79 80void 81sata_request::SetATA48Command(uint8 command, uint64 lba, uint16 sectorCount) 82{ 83 SetATACommand(command); 84 fFis[4] = lba & 0xff; 85 fFis[5] = (lba >> 8) & 0xff; 86 fFis[6] = (lba >> 16) & 0xff; 87 fFis[7] = 0x40; 88 // device 89 fFis[8] = (lba >> 24) & 0xff; 90 fFis[9] = (lba >> 32) & 0xff; 91 fFis[10] = (lba >> 40) & 0xff; 92 fFis[12] = sectorCount & 0xff; 93 fFis[13] = (sectorCount >> 8) & 0xff; 94} 95 96 97void 98sata_request::SetFeature(uint16 feature) 99{ 100 fFis[3] = (uint8)(feature & 0xff); 101 fFis[11] = (uint8)(feature >> 8); 102} 103 104 105void 106sata_request::SetATAPICommand(size_t transferLength) 107{ 108 fIsATAPI = true; 109 SetATACommand(0xa0); 110 if (1 /* isPIO */) { 111 if (transferLength == 0) 112 transferLength = 2; 113 else if (transferLength > 0xfffe) 114 transferLength = 0xfffe; 115 fFis[5] = transferLength & 0xff; 116 fFis[6] = (transferLength >> 8) & 0xff; 117 } 118} 119 120 121void 122sata_request::Finish(int tfd, size_t bytesTransfered) 123{ 124 if ((tfd & (ATA_STATUS_ERROR | ATA_STATUS_DEVICE_FAULT)) != 0) { 125 uint8 status = tfd & 0xff; 126 uint8 error = (tfd >> 8) & 0xff; 127 128 if (!IsTestUnitReady()) { 129 dprintf("ahci: sata_request::finish ATA command 0x%02x failed:" 130 " status 0x%02x, error 0x%02x\n", fFis[2], status, error); 131 } 132 } 133 134 if (fCcb) { 135 fCcb->data_resid = fCcb->data_length - bytesTransfered; 136 fCcb->device_status = SCSI_STATUS_GOOD; 137 fCcb->subsys_status = SCSI_REQ_CMP; 138 if (tfd & (ATA_STATUS_ERROR | ATA_STATUS_DEVICE_FAULT)) { 139 fCcb->subsys_status = SCSI_REQ_CMP_ERR; 140 if (fIsATAPI) { 141 if (!IsTestUnitReady()) { 142 dprintf("ahci: sata_request::finish ATAPI packet %02x %02x " 143 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x " 144 "%02x %02x %02x %02x (len %d)\n", 145 fCcb->cdb[0], fCcb->cdb[1], fCcb->cdb[2], fCcb->cdb[3], 146 fCcb->cdb[4], fCcb->cdb[5], fCcb->cdb[6], fCcb->cdb[7], 147 fCcb->cdb[8], fCcb->cdb[9], fCcb->cdb[10], 148 fCcb->cdb[11], fCcb->cdb[12], fCcb->cdb[13], 149 fCcb->cdb[14], fCcb->cdb[15], fCcb->cdb_length); 150 } 151 152 fCcb->device_status = SCSI_STATUS_CHECK_CONDITION; 153 } else { 154 // TODO ATA error handling goes here 155/* 156 // TODO check ABORT bit if this is useful 157 if ((tfd >> 8) & 0x04) { // ABRT 158 fCcb->subsys_status = SCSI_REQ_ABORTED; 159 } else { 160 fCcb->device_status = SCSI_STATUS_CHECK_CONDITION; 161 fCcb->subsys_status |= SCSI_AUTOSNS_VALID; 162 fCcb->sense_resid = 0; //FIXME 163 scsi_sense *sense = (scsi_sense *)fCcb->sense; 164 sense->error_code = SCSIS_CURR_ERROR; 165 sense->sense_key = error >> 4; 166 sense->asc = 0; 167 sense->ascq = 0; 168 } 169*/ 170 } 171 } 172 gSCSI->finished(fCcb, 1); 173 delete this; 174 } else { 175 fCompletionStatus = tfd; 176 release_sem(fCompletionSem); 177 } 178} 179 180 181void 182sata_request::Abort() 183{ 184 dprintf("ahci: sata_request::abort called for command 0x%02x\n", fFis[2]); 185 if (fCcb != NULL) { 186 fCcb->subsys_status = SCSI_REQ_ABORTED; 187 gSCSI->finished(fCcb, 1); 188 delete this; 189 } else { 190 fCompletionStatus = ATA_STATUS_ERROR; 191 release_sem(fCompletionSem); 192 } 193} 194 195 196void 197sata_request::WaitForCompletion() 198{ 199 ASSERT(fCcb == NULL); 200 acquire_sem(fCompletionSem); 201} 202 203 204int 205sata_request::CompletionStatus() 206{ 207 ASSERT(fCcb == NULL); 208 return fCompletionStatus; 209} 210