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 sata_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 25 sata_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 37 sata_request::~sata_request() 38 { 39 if (fCompletionSem >= 0) 40 delete_sem(fCompletionSem); 41 } 42 43 44 void 45 sata_request::set_data(void *data, size_t dataSize) 46 { 47 if (fCcb) panic("wrong usage"); 48 fData = data; 49 fDataSize = dataSize; 50 } 51 52 53 void 54 sata_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 63 void 64 sata_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 75 void 76 sata_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 91 void 92 sata_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 107 void 108 sata_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 169 void 170 sata_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 184 void 185 sata_request::wait_for_completition() 186 { 187 if (fCcb) panic("wrong usage"); 188 acquire_sem(fCompletionSem); 189 } 190 191 192 int 193 sata_request::completition_status() 194 { 195 if (fCcb) panic("wrong usage"); 196 return fCompletionStatus; 197 } 198