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