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 109 if (!is_test_unit_ready()) { 110 dprintf("ahci: sata_request::finish ATA command 0x%02x failed\n", 111 fFis[2]); 112 dprintf("ahci: sata_request::finish status 0x%02x, error 0x%02x\n", 113 status, error); 114 } 115 } 116 117 if (fCcb) { 118 fCcb->data_resid = fCcb->data_length - bytesTransfered; 119 fCcb->device_status = SCSI_STATUS_GOOD; 120 fCcb->subsys_status = SCSI_REQ_CMP; 121 if (tfd & (ATA_ERR | ATA_DF)) { 122 fCcb->subsys_status = SCSI_REQ_CMP_ERR; 123 if (fIsATAPI) { 124 if (!is_test_unit_ready()) { 125 dprintf("ahci: sata_request::finish ATAPI packet %02x %02x %02x %02x " 126 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x (len %d)\n", 127 fCcb->cdb[0], fCcb->cdb[1], fCcb->cdb[2], fCcb->cdb[3], 128 fCcb->cdb[4], fCcb->cdb[5], fCcb->cdb[6], fCcb->cdb[7], 129 fCcb->cdb[8], fCcb->cdb[9], fCcb->cdb[10], fCcb->cdb[11], 130 fCcb->cdb[12], fCcb->cdb[13], fCcb->cdb[14], fCcb->cdb[15], 131 fCcb->cdb_length); 132 } 133 134 fCcb->device_status = SCSI_STATUS_CHECK_CONDITION; 135 } else { 136 // TODO ATA error handling goes here 137 /* 138 // TODO check ABORT bit if this is useful 139 if ((tfd >> 8) & 0x04) { // ABRT 140 fCcb->subsys_status = SCSI_REQ_ABORTED; 141 } else { 142 fCcb->device_status = SCSI_STATUS_CHECK_CONDITION; 143 fCcb->subsys_status |= SCSI_AUTOSNS_VALID; 144 fCcb->sense_resid = 0; //FIXME 145 scsi_sense *sense = (scsi_sense *)fCcb->sense; 146 sense->error_code = SCSIS_CURR_ERROR; 147 sense->sense_key = error >> 4; 148 sense->asc = 0; 149 sense->ascq = 0; 150 } 151 */ 152 } 153 } 154 gSCSI->finished(fCcb, 1); 155 delete this; 156 } else { 157 fCompletionStatus = tfd; 158 release_sem(fCompletionSem); 159 } 160 } 161 162 163 void 164 sata_request::abort() 165 { 166 dprintf("ahci: sata_request::abort called for command 0x%02x\n", fFis[2]); 167 if (fCcb) { 168 fCcb->subsys_status = SCSI_REQ_ABORTED; 169 gSCSI->finished(fCcb, 1); 170 delete this; 171 } else { 172 fCompletionStatus = ATA_ERR; 173 release_sem(fCompletionSem); 174 } 175 } 176 177 178 void 179 sata_request::wait_for_completition() 180 { 181 if (fCcb) panic("wrong usage"); 182 acquire_sem(fCompletionSem); 183 } 184 185 186 int 187 sata_request::completition_status() 188 { 189 if (fCcb) panic("wrong usage"); 190 return fCompletionStatus; 191 } 192 193 194 195 196 197 198