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