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 16 sata_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 28 sata_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 40 sata_request::~sata_request() 41 { 42 if (fCompletionSem >= 0) 43 delete_sem(fCompletionSem); 44 } 45 46 47 void 48 sata_request::SetData(void* data, size_t dataSize) 49 { 50 ASSERT(fCcb == NULL); 51 fData = data; 52 fDataSize = dataSize; 53 } 54 55 56 void 57 sata_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 67 void 68 sata_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 80 void 81 sata_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 97 void 98 sata_request::SetFeature(uint16 feature) 99 { 100 fFis[3] = (uint8)(feature & 0xff); 101 fFis[11] = (uint8)(feature >> 8); 102 } 103 104 105 void 106 sata_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 121 void 122 sata_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 181 void 182 sata_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 196 void 197 sata_request::WaitForCompletion() 198 { 199 ASSERT(fCcb == NULL); 200 acquire_sem(fCompletionSem); 201 } 202 203 204 int 205 sata_request::CompletionStatus() 206 { 207 ASSERT(fCcb == NULL); 208 return fCompletionStatus; 209 } 210