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() 88 { 89 fIsATAPI = true; 90 set_ata_cmd(0xa0); 91 fFis[5] = 0xfe; 92 fFis[6] = 0xff; 93 } 94 95 96 void 97 sata_request::finish(int tfd, size_t bytesTransfered) 98 { 99 if (tfd & ATA_ERR) 100 dprintf("ahci: sata_request::finish ATA_ERR set for command 0x%02x\n", fFis[2]); 101 if (fCcb) { 102 fCcb->data_resid = fCcb->data_length - bytesTransfered; 103 fCcb->subsys_status = SCSI_REQ_CMP; 104 if (tfd & (ATA_ERR | ATA_DF)) { 105 uint8 error = (tfd >> 8) & 0xff; 106 dprintf("ahci: sata_request::finish status 0x%02x, error 0x%02x\n", tfd & 0xff, error); 107 if (fIsATAPI) { 108 fCcb->subsys_status = SCSI_REQ_CMP_ERR; 109 fCcb->device_status = SCSI_STATUS_CHECK_CONDITION; 110 } else { 111 fCcb->subsys_status = SCSI_REQ_CMP_ERR; 112 // TODO error handling goes here 113 } 114 /* 115 if (error & 0x04) { // ABRT 116 fCcb->subsys_status = SCSI_REQ_ABORTED; 117 } else { 118 fCcb->device_status = SCSI_STATUS_CHECK_CONDITION; 119 fCcb->subsys_status |= SCSI_AUTOSNS_VALID; 120 fCcb->sense_resid = 0; //FIXME 121 scsi_sense *sense = (scsi_sense *)fCcb->sense; 122 sense->error_code = SCSIS_CURR_ERROR; 123 sense->sense_key = error >> 4; 124 sense->asc = 0; 125 sense->ascq = 0; 126 } 127 */ 128 } 129 gSCSI->finished(fCcb, 1); 130 delete this; 131 } else { 132 fCompletionStatus = tfd; 133 release_sem(fCompletionSem); 134 } 135 } 136 137 138 void 139 sata_request::abort() 140 { 141 dprintf("ahci: sata_request::abort called for command 0x%02x\n", fFis[2]); 142 if (fCcb) { 143 fCcb->subsys_status = SCSI_REQ_ABORTED; 144 gSCSI->finished(fCcb, 1); 145 delete this; 146 } else { 147 fCompletionStatus = -1; 148 release_sem(fCompletionSem); 149 } 150 } 151 152 153 void 154 sata_request::wait_for_completition() 155 { 156 if (fCcb) panic("wrong usage"); 157 acquire_sem(fCompletionSem); 158 } 159 160 161 int 162 sata_request::completition_status() 163 { 164 if (fCcb) panic("wrong usage"); 165 return fCompletionStatus; 166 } 167 168 169 170 171 172 173